Merge "Use getOrCreateRootHomeTask in ActivityStartController" into rvc-dev
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 170cac4..5052499 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -48,7 +48,6 @@
":opt-telephony-srcs",
":opt-net-voip-srcs",
":art-module-public-api-stubs-source",
- ":conscrypt.module.public.api.stubs.source",
":android_icu4j_public_api_files",
],
// TODO(b/147699819): remove below aidl includes.
@@ -69,7 +68,10 @@
stubs_defaults {
name: "metalava-full-api-stubs-default",
defaults: ["metalava-base-api-stubs-default"],
- srcs: [":framework-updatable-sources"],
+ srcs: [
+ ":conscrypt.module.public.api.stubs.source",
+ ":framework-updatable-sources",
+ ],
sdk_version: "core_platform",
}
@@ -110,7 +112,7 @@
},
last_released: {
api_file: ":android.api.public.latest",
- removed_api_file: "api/removed.txt",
+ removed_api_file: ":removed.api.public.latest",
baseline_file: ":public-api-incompatibilities-with-last-released",
},
api_lint: {
@@ -152,7 +154,7 @@
},
last_released: {
api_file: ":android.api.system.latest",
- removed_api_file: "api/system-removed.txt",
+ removed_api_file: ":removed.api.system.latest",
baseline_file: ":system-api-incompatibilities-with-last-released"
},
api_lint: {
@@ -216,7 +218,7 @@
},
last_released: {
api_file: ":android.api.module-lib.latest",
- removed_api_file: "api/module-lib-removed.txt",
+ removed_api_file: ":removed.api.module-lib.latest",
baseline_file: ":module-lib-api-incompatibilities-with-last-released"
},
api_lint: {
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 478cfc1..1b28913 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -25,9 +25,4 @@
<option name="package" value="com.android.perftests.core" />
<option name="hidden-api-checks" value="false"/>
</test>
-
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/data/local/CorePerfTests" />
- <option name="collect-on-run-ended-only" value="true" />
- </metrics_collector>
</configuration>
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
new file mode 100644
index 0000000..f02cbcf
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -0,0 +1,26 @@
+// 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: "WmPerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ ],
+ test_suites: ["device-tests"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml
new file mode 100644
index 0000000..7198176
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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.perftests.wm">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.perftests.utils.PerfTestActivity">
+ <intent-filter>
+ <action android:name="com.android.perftests.core.PERFTEST" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.wm"/>
+</manifest>
diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml
new file mode 100644
index 0000000..69d187f
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?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="Runs WmPerfTests 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.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="WmPerfTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.wm" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/local/WmPerfTests" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
similarity index 95%
rename from apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 836e6b6..1667c165 100644
--- a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -46,6 +46,7 @@
import org.junit.AfterClass;
import org.junit.Assume;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
@@ -72,6 +73,12 @@
private long mMeasuredTimeNs;
+ /**
+ * Used to skip each test method if there is error. It cannot be raised in static setup because
+ * that will break the amount of target method count.
+ */
+ private static Exception sSetUpClassException;
+
@Parameterized.Parameter(0)
public int intervalBetweenOperations;
@@ -107,15 +114,21 @@
sRecentsIntent =
new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
} catch (Exception e) {
- Assume.assumeNoException(e);
+ sSetUpClassException = e;
}
}
@AfterClass
public static void tearDownClass() {
+ sSetUpClassException = null;
sUiAutomation.dropShellPermissionIdentity();
}
+ @Before
+ public void setUp() {
+ Assume.assumeNoException(sSetUpClassException);
+ }
+
/** Simulate the timing of touch. */
private void makeInterval() {
SystemClock.sleep(intervalBetweenOperations);
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
rename to apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
diff --git a/apex/Android.bp b/apex/Android.bp
index 67cd0d7..f511af5 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -63,6 +63,63 @@
"--hide-annotation android.annotation.Hide " +
"--hide InternalClasses " // com.android.* classes are okay in this interface
+// Defaults for mainline module provided java_sdk_library instances.
+java_defaults {
+ name: "framework-module-defaults",
+
+ // Additional annotations used for compiling both the implementation and the
+ // stubs libraries.
+ libs: ["framework-annotations-lib"],
+
+ // Enable api lint. This will eventually become the default for java_sdk_library
+ // but it cannot yet be turned on because some usages have not been cleaned up.
+ // TODO(b/156126315) - Remove when no longer needed.
+ api_lint: {
+ enabled: true,
+ },
+
+ // The API scope specific properties.
+ public: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ system: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ module_lib: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+
+ // Configure framework module specific metalava options.
+ droiddoc_options: [mainline_stubs_args],
+
+ // The stub libraries must be visible to frameworks/base so they can be combined
+ // into API specific libraries.
+ stubs_library_visibility: [
+ "//frameworks/base", // Framework
+ ],
+
+ // Set the visibility of the modules creating the stubs source.
+ stubs_source_visibility: [
+ // Ignore any visibility rules specified on the java_sdk_library when
+ // setting the visibility of the stubs source modules.
+ "//visibility:override",
+
+ // Currently, the stub source is not required for anything other than building
+ // the stubs library so is private to avoid misuse.
+ "//visibility:private",
+ ],
+
+ // Collates API usages from each module for further analysis.
+ plugins: ["java_api_finder"],
+
+ // Mainline modules should only rely on 'module_lib' APIs provided by other modules
+ // and the non updatable parts of the platform.
+ sdk_version: "module_current",
+}
+
stubs_defaults {
name: "framework-module-stubs-defaults-publicapi",
args: mainline_framework_stubs_args,
@@ -74,6 +131,9 @@
api_file: "api/current.txt",
removed_api_file: "api/removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
@@ -93,6 +153,9 @@
api_file: "api/system-current.txt",
removed_api_file: "api/system-removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
@@ -147,6 +210,9 @@
api_file: "api/module-lib-current.txt",
removed_api_file: "api/module-lib-removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
@@ -173,6 +239,9 @@
api_file: "api/current.txt",
removed_api_file: "api/removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
diff --git a/apex/extservices/Android.bp b/apex/extservices/Android.bp
index 68350af..0c6c4c2 100644
--- a/apex/extservices/Android.bp
+++ b/apex/extservices/Android.bp
@@ -21,7 +21,7 @@
apex_defaults {
name: "com.android.extservices-defaults",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "current",
key: "com.android.extservices.key",
certificate: ":com.android.extservices.certificate",
apps: ["ExtServices"],
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 6d9e3ed..887d82c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -45,6 +45,14 @@
boolean idle, int bucket, int reason);
/**
+ * Callback to inform listeners that the parole state has changed. This means apps are
+ * allowed to do work even if they're idle or in a low bucket.
+ */
+ public void onParoleStateChanged(boolean isParoleOn) {
+ // No-op by default
+ }
+
+ /**
* Optional callback to inform the listener that the app has transitioned into
* an active state due to user interaction.
*/
@@ -92,6 +100,11 @@
boolean isAppIdleFiltered(String packageName, int appId, int userId,
long elapsedRealtime);
+ /**
+ * @return true if currently app idle parole mode is on.
+ */
+ boolean isInParole();
+
int[] getIdleUidsForUser(int userId);
void setAppIdleAsync(String packageName, boolean idle, int userId);
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 2aa2275..e888651 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -56,6 +56,7 @@
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
+import android.os.LimitExceededException;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -1002,7 +1003,7 @@
}
if (isDebuggable) {
// Only throw the exception for debuggable apps.
- throw new IllegalStateException(
+ throw new LimitExceededException(
"schedule()/enqueue() called more than "
+ mQuotaTracker.getLimit(Category.SINGLE_CATEGORY)
+ " times in the past "
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 46d449a..372ec98 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -79,6 +79,12 @@
private static final int STANDBY_BUCKET_UNKNOWN = -1;
+ /**
+ * The bucket beyond which apps are considered idle. Any apps in this bucket or lower are
+ * considered idle while those in higher buckets are not considered idle.
+ */
+ static final int IDLE_BUCKET_CUTOFF = STANDBY_BUCKET_RARE;
+
@VisibleForTesting
static final String APP_IDLE_FILENAME = "app_idle_stats.xml";
private static final String TAG_PACKAGES = "packages";
@@ -350,7 +356,7 @@
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
getPackageHistory(userHistory, packageName, elapsedRealtime, true);
- return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE;
+ return appUsageHistory.currentBucket >= IDLE_BUCKET_CUTOFF;
}
public AppUsageHistory getAppUsageHistory(String packageName, int userId,
@@ -487,7 +493,7 @@
final int newBucket;
final int reason;
if (idle) {
- newBucket = STANDBY_BUCKET_RARE;
+ newBucket = IDLE_BUCKET_CUTOFF;
reason = REASON_MAIN_FORCED_BY_USER;
} else {
newBucket = STANDBY_BUCKET_ACTIVE;
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 24728dd..94e5d0b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -54,6 +54,7 @@
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -92,6 +93,7 @@
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -214,8 +216,7 @@
private AppIdleHistory mAppIdleHistory;
@GuardedBy("mPackageAccessListeners")
- private ArrayList<AppIdleStateChangeListener>
- mPackageAccessListeners = new ArrayList<>();
+ private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
/** Whether we've queried the list of carrier privileged apps. */
@GuardedBy("mAppIdleLock")
@@ -228,6 +229,13 @@
@GuardedBy("mActiveAdminApps")
private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
+ /**
+ * Set of system apps that are headless (don't have any declared activities, enabled or
+ * disabled). Presence in this map indicates that the app is a headless system app.
+ */
+ @GuardedBy("mAppIdleLock")
+ private final ArrayMap<String, Boolean> mHeadlessSystemApps = new ArrayMap<>();
+
private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
// Messages for the handler
@@ -235,6 +243,7 @@
static final int MSG_FORCE_IDLE_STATE = 4;
static final int MSG_CHECK_IDLE_STATES = 5;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
+ static final int MSG_PAROLE_STATE_CHANGED = 9;
static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
/** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
@@ -293,6 +302,13 @@
* {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
*/
boolean mLinkCrossProfileApps;
+ /**
+ * Whether we should allow apps into the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
+ * If false, any attempts to put an app into the bucket will put the app into the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead.
+ */
+ private boolean mAllowRestrictedBucket;
private volatile boolean mAppIdleEnabled;
private boolean mIsCharging;
@@ -390,7 +406,16 @@
@VisibleForTesting
void setAppIdleEnabled(boolean enabled) {
- mAppIdleEnabled = enabled;
+ synchronized (mAppIdleLock) {
+ if (mAppIdleEnabled != enabled) {
+ final boolean oldParoleState = isInParole();
+ mAppIdleEnabled = enabled;
+ if (isInParole() != oldParoleState) {
+ postParoleStateChanged();
+ }
+ }
+ }
+
}
@Override
@@ -563,11 +588,23 @@
if (mIsCharging != isCharging) {
if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
mIsCharging = isCharging;
+ postParoleStateChanged();
}
}
}
@Override
+ public boolean isInParole() {
+ return !mAppIdleEnabled || mIsCharging;
+ }
+
+ private void postParoleStateChanged() {
+ if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
+ mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
+ mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
+ }
+
+ @Override
public void postCheckIdleStates(int userId) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
@@ -639,20 +676,22 @@
return;
}
}
- final boolean isSpecial = isAppSpecial(packageName,
+ final int minBucket = getAppMinBucket(packageName,
UserHandle.getAppId(uid),
userId);
if (DEBUG) {
- Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
- isSpecial);
+ Slog.d(TAG, " Checking idle state for " + packageName
+ + " minBucket=" + minBucket);
}
- if (isSpecial) {
+ if (minBucket <= STANDBY_BUCKET_ACTIVE) {
+ // No extra processing needed for ACTIVE or higher since apps can't drop into lower
+ // buckets.
synchronized (mAppIdleLock) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
+ minBucket, REASON_MAIN_DEFAULT);
}
maybeInformListeners(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false);
+ minBucket, REASON_MAIN_DEFAULT, false);
} else {
synchronized (mAppIdleLock) {
final AppIdleHistory.AppUsageHistory app =
@@ -667,6 +706,10 @@
return;
}
final int oldBucket = app.currentBucket;
+ if (oldBucket == STANDBY_BUCKET_NEVER) {
+ // None of this should bring an app out of the NEVER bucket.
+ return;
+ }
int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
// Compute age-based bucket
@@ -722,11 +765,26 @@
Slog.d(TAG, "Bringing down to RESTRICTED due to timeout");
}
}
+ if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
+ newBucket = STANDBY_BUCKET_RARE;
+ // Leave the reason alone.
+ if (DEBUG) {
+ Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch");
+ }
+ }
+ if (newBucket > minBucket) {
+ newBucket = minBucket;
+ // Leave the reason alone.
+ if (DEBUG) {
+ Slog.d(TAG, "Bringing up from " + newBucket + " to " + minBucket
+ + " due to min bucketing");
+ }
+ }
if (DEBUG) {
Slog.d(TAG, " Old bucket=" + oldBucket
+ ", newBucket=" + newBucket);
}
- if (oldBucket < newBucket || predictionLate) {
+ if (oldBucket != newBucket || predictionLate) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId,
elapsedRealtime, newBucket, reason);
maybeInformListeners(packageName, userId, elapsedRealtime,
@@ -988,20 +1046,35 @@
return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
}
- private boolean isAppSpecial(String packageName, int appId, int userId) {
- if (packageName == null) return false;
+ @StandbyBuckets
+ private int getAppMinBucket(String packageName, int userId) {
+ try {
+ final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Not a valid package for this user, nothing to do
+ return STANDBY_BUCKET_NEVER;
+ }
+ }
+
+ /**
+ * Return the lowest bucket this app should ever enter.
+ */
+ @StandbyBuckets
+ private int getAppMinBucket(String packageName, int appId, int userId) {
+ if (packageName == null) return STANDBY_BUCKET_NEVER;
// If not enabled at all, of course nobody is ever idle.
if (!mAppIdleEnabled) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (appId < Process.FIRST_APPLICATION_UID) {
// System uids never go idle.
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (packageName.equals("android")) {
// Nor does the framework (which should be redundant with the above, but for MR1 we will
// retain this for safety).
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (mSystemServicesReady) {
try {
@@ -1009,42 +1082,50 @@
// for idle mode, because app idle (aka app standby) is really not as big an issue
// for controlling who participates vs. doze mode.
if (mInjector.isNonIdleWhitelisted(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
if (isActiveDeviceAdmin(packageName, userId)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (isActiveNetworkScorer(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (mAppWidgetManager != null
&& mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
- return true;
+ return STANDBY_BUCKET_ACTIVE;
}
if (isDeviceProvisioningPackage(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
}
// Check this last, as it can be the most expensive check
if (isCarrierApp(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
- return false;
+ if (isHeadlessSystemApp(packageName)) {
+ return STANDBY_BUCKET_ACTIVE;
+ }
+
+ return STANDBY_BUCKET_NEVER;
+ }
+
+ private boolean isHeadlessSystemApp(String packageName) {
+ return mHeadlessSystemApps.containsKey(packageName);
}
@Override
public boolean isAppIdleFiltered(String packageName, int appId, int userId,
long elapsedRealtime) {
- if (isAppSpecial(packageName, appId, userId)) {
+ if (getAppMinBucket(packageName, appId, userId) < AppIdleHistory.IDLE_BUCKET_CUTOFF) {
return false;
} else {
synchronized (mAppIdleLock) {
@@ -1176,8 +1257,8 @@
final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
final long nowElapsed = mInjector.elapsedRealtime();
- setAppStandbyBucket(packageName, userId, STANDBY_BUCKET_RESTRICTED, reason,
- nowElapsed, false);
+ final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;
+ setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false);
}
@Override
@@ -1247,6 +1328,9 @@
Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName);
return;
}
+ if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
+ newBucket = STANDBY_BUCKET_RARE;
+ }
AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
userId, elapsedRealtime);
boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
@@ -1365,6 +1449,7 @@
Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
}
} else if (newBucket == STANDBY_BUCKET_RARE
+ && mAllowRestrictedBucket
&& getBucketForLocked(packageName, userId, elapsedRealtime)
== STANDBY_BUCKET_RESTRICTED) {
// Prediction doesn't think the app will be used anytime soon and
@@ -1380,6 +1465,8 @@
}
}
+ // Make sure we don't put the app in a lower bucket than it's supposed to be in.
+ newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId));
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
reason, resetTimeout);
}
@@ -1502,6 +1589,15 @@
}
}
+ private void informParoleStateChanged() {
+ final boolean paroled = isInParole();
+ synchronized (mPackageAccessListeners) {
+ for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
+ listener.onParoleStateChanged(paroled);
+ }
+ }
+ }
+
@Override
public void flushToDisk(int userId) {
synchronized (mAppIdleLock) {
@@ -1565,14 +1661,16 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
+ final String pkgName = intent.getData().getSchemeSpecificPart();
+ final int userId = getSendingUserId();
if (Intent.ACTION_PACKAGE_ADDED.equals(action)
|| Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
clearCarrierPrivilegedApps();
+ // ACTION_PACKAGE_ADDED is called even for system app downgrades.
+ evaluateSystemAppException(pkgName, userId);
}
if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Intent.ACTION_PACKAGE_ADDED.equals(action))) {
- final String pkgName = intent.getData().getSchemeSpecificPart();
- final int userId = getSendingUserId();
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
maybeUnrestrictBuggyApp(pkgName, userId);
} else {
@@ -1582,6 +1680,34 @@
}
}
+ private void evaluateSystemAppException(String packageName, int userId) {
+ if (!mSystemServicesReady) {
+ // The app will be evaluated in initializeDefaultsForSystemApps() when possible.
+ return;
+ }
+ try {
+ PackageInfo pi = mPackageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS,
+ userId);
+ evaluateSystemAppException(pi);
+ } catch (PackageManager.NameNotFoundException e) {
+ mHeadlessSystemApps.remove(packageName);
+ }
+ }
+
+ private void evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
+ if (pkgInfo.applicationInfo != null && pkgInfo.applicationInfo.isSystemApp()) {
+ synchronized (mAppIdleLock) {
+ if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
+ // Headless system app.
+ mHeadlessSystemApps.put(pkgInfo.packageName, true);
+ } else {
+ mHeadlessSystemApps.remove(pkgInfo.packageName);
+ }
+ }
+ }
+ }
+
@Override
public void initializeDefaultsForSystemApps(int userId) {
if (!mSystemServicesReady) {
@@ -1593,7 +1719,7 @@
+ "appIdleEnabled=" + mAppIdleEnabled);
final long elapsedRealtime = mInjector.elapsedRealtime();
List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.MATCH_DISABLED_COMPONENTS,
+ PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS,
userId);
final int packageCount = packages.size();
synchronized (mAppIdleLock) {
@@ -1606,6 +1732,8 @@
mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
+
+ evaluateSystemAppException(pi);
}
}
// Immediately persist defaults to disk
@@ -1697,6 +1825,8 @@
pw.println();
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
+ pw.print(" mAllowRestrictedBucket=");
+ pw.print(mAllowRestrictedBucket);
pw.print(" mIsCharging=");
pw.print(mIsCharging);
pw.println();
@@ -1798,6 +1928,12 @@
return mPowerWhitelistManager.isWhitelisted(packageName, false);
}
+ boolean isRestrictedBucketEnabled() {
+ return Global.getInt(mContext.getContentResolver(),
+ Global.ENABLE_RESTRICTED_BUCKET,
+ Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1;
+ }
+
File getDataSystemDirectory() {
return Environment.getDataSystemDirectory();
}
@@ -1920,6 +2056,11 @@
args.recycle();
break;
+ case MSG_PAROLE_STATE_CHANGED:
+ if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole());
+ informParoleStateChanged();
+ break;
+
case MSG_CHECK_PACKAGE_IDLE_STATE:
checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
mInjector.elapsedRealtime());
@@ -2031,6 +2172,8 @@
final ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
+ cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET),
+ false, this);
cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
false, this);
}
@@ -2129,6 +2272,8 @@
mLinkCrossProfileApps = mParser.getBoolean(
KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);
+
+ mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled();
}
// Check if app_idle_enabled has changed. Do this after getting the rest of the settings
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index a1c886a..3bc4f7b 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -102,6 +102,15 @@
"framework-media-stubs-srcs-defaults",
"framework-module-stubs-defaults-publicapi",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-media.api.public.latest",
+ removed_api_file: ":framework-media-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-media.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -110,6 +119,15 @@
"framework-media-stubs-srcs-defaults",
"framework-module-stubs-defaults-systemapi",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-media.api.system.latest",
+ removed_api_file: ":framework-media-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-media.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -118,6 +136,15 @@
"framework-media-stubs-srcs-defaults",
"framework-module-api-defaults-module_libs_api",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-media.api.module-lib.latest",
+ removed_api_file: ":framework-media-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-media.api.module-lib.latest",
+ },
+ },
}
droidstubs {
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index a9ed6d8..c1011ec 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.media.MediaCodec.CryptoInfo;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -65,6 +66,7 @@
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -466,7 +468,24 @@
public @interface SampleFlags {}
/** Indicates that the sample holds a synchronization sample. */
public static final int SAMPLE_FLAG_KEY_FRAME = MediaCodec.BUFFER_FLAG_KEY_FRAME;
- /** Indicates that the sample has supplemental data. */
+ /**
+ * Indicates that the sample has supplemental data.
+ *
+ * <p>Samples will not have this flag set unless the {@code
+ * "android.media.mediaparser.includeSupplementalData"} parameter is set to {@code true} via
+ * {@link #setParameter}.
+ *
+ * <p>Samples with supplemental data have the following sample data format:
+ *
+ * <ul>
+ * <li>If the {@code "android.media.mediaparser.inBandCryptoInfo"} parameter is set, all
+ * encryption information.
+ * <li>(4 bytes) {@code sample_data_size}: The size of the actual sample data, not including
+ * supplemental data or encryption information.
+ * <li>({@code sample_data_size} bytes): The media sample data.
+ * <li>(remaining bytes) The supplemental data.
+ * </ul>
+ */
public static final int SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA = 1 << 28;
/** Indicates that the sample is known to contain the last media sample of the stream. */
public static final int SAMPLE_FLAG_LAST_SAMPLE = 1 << 29;
@@ -577,7 +596,9 @@
PARAMETER_TS_IGNORE_AVC_STREAM,
PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM,
PARAMETER_TS_DETECT_ACCESS_UNITS,
- PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS
+ PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS,
+ PARAMETER_IN_BAND_CRYPTO_INFO,
+ PARAMETER_INCLUDE_SUPPLEMENTAL_DATA
})
public @interface ParameterName {}
@@ -709,6 +730,45 @@
*/
public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS =
"android.media.mediaparser.ts.enableHdmvDtsAudioStreams";
+ /**
+ * Sets whether encryption data should be sent in-band with the sample data, as per {@link
+ * OutputConsumer#onSampleDataFound}. {@code boolean} expected. Default value is {@code false}.
+ *
+ * <p>If this parameter is set, encrypted samples' data will be prefixed with the encryption
+ * information bytes. The format for in-band encryption information is:
+ *
+ * <ul>
+ * <li>(1 byte) {@code encryption_signal_byte}: Most significant bit signals whether the
+ * encryption data contains subsample encryption data. The remaining bits contain {@code
+ * initialization_vector_size}.
+ * <li>({@code initialization_vector_size} bytes) Initialization vector.
+ * <li>If subsample encryption data is present, as per {@code encryption_signal_byte}, the
+ * encryption data also contains:
+ * <ul>
+ * <li>(2 bytes) {@code subsample_encryption_data_length}.
+ * <li>({@code subsample_encryption_data_length * 6} bytes) Subsample encryption data
+ * (repeated {@code subsample_encryption_data_length} times):
+ * <ul>
+ * <li>(2 bytes) Size of a clear section in sample.
+ * <li>(4 bytes) Size of an encryption section in sample.
+ * </ul>
+ * </ul>
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String PARAMETER_IN_BAND_CRYPTO_INFO =
+ "android.media.mediaparser.inBandCryptoInfo";
+
+ /**
+ * Sets whether supplemental data should be included as part of the sample data. {@code boolean}
+ * expected. Default value is {@code false}. See {@link #SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA} for
+ * information about the sample data format.
+ *
+ * @hide
+ */
+ public static final String PARAMETER_INCLUDE_SUPPLEMENTAL_DATA =
+ "android.media.mediaparser.includeSupplementalData";
// Private constants.
@@ -718,6 +778,21 @@
private static final String TS_MODE_SINGLE_PMT = "single_pmt";
private static final String TS_MODE_MULTI_PMT = "multi_pmt";
private static final String TS_MODE_HLS = "hls";
+ private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6;
+
+ @IntDef(
+ value = {
+ STATE_READING_SIGNAL_BYTE,
+ STATE_READING_INIT_VECTOR,
+ STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE,
+ STATE_READING_SUBSAMPLE_ENCRYPTION_DATA
+ })
+ private @interface EncryptionDataReadState {}
+
+ private static final int STATE_READING_SIGNAL_BYTE = 0;
+ private static final int STATE_READING_INIT_VECTOR = 1;
+ private static final int STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE = 2;
+ private static final int STATE_READING_SUBSAMPLE_ENCRYPTION_DATA = 3;
// Instance creation methods.
@@ -853,6 +928,8 @@
private final DataReaderAdapter mScratchDataReaderAdapter;
private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter;
@Nullable private final Constructor<DrmInitData.SchemeInitData> mSchemeInitDataConstructor;
+ private boolean mInBandCryptoInfo;
+ private boolean mIncludeSupplementalData;
private String mParserName;
private Extractor mExtractor;
private ExtractorInput mExtractorInput;
@@ -900,6 +977,12 @@
&& !TS_MODE_MULTI_PMT.equals(value)) {
throw new IllegalArgumentException(PARAMETER_TS_MODE + " does not accept: " + value);
}
+ if (PARAMETER_IN_BAND_CRYPTO_INFO.equals(parameterName)) {
+ mInBandCryptoInfo = (boolean) value;
+ }
+ if (PARAMETER_INCLUDE_SUPPLEMENTAL_DATA.equals(parameterName)) {
+ mIncludeSupplementalData = (boolean) value;
+ }
mParserParameters.put(parameterName, value);
return this;
}
@@ -1050,6 +1133,9 @@
// Private methods.
private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ throw new UnsupportedOperationException("Android version must be R or greater.");
+ }
mParserParameters = new HashMap<>();
mOutputConsumer = outputConsumer;
mParserNamesPool = parserNamesPool;
@@ -1274,9 +1360,24 @@
private class TrackOutputAdapter implements TrackOutput {
private final int mTrackIndex;
+ private final CryptoInfo mCryptoInfo;
+
+ @EncryptionDataReadState private int mEncryptionDataReadState;
+ private int mEncryptionDataSizeToSubtractFromSampleDataSize;
+ private int mEncryptionVectorSize;
+ private boolean mHasSubsampleEncryptionData;
+ private CryptoInfo.Pattern mEncryptionPattern;
+ private int mSkippedSupplementalDataBytes;
private TrackOutputAdapter(int trackIndex) {
mTrackIndex = trackIndex;
+ mCryptoInfo = new CryptoInfo();
+ mCryptoInfo.iv = new byte[16]; // Size documented in CryptoInfo.
+ mCryptoInfo.numBytesOfClearData = new int[0];
+ mCryptoInfo.numBytesOfEncryptedData = new int[0];
+ mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
+ mEncryptionPattern =
+ new CryptoInfo.Pattern(/* blocksToEncrypt= */ 0, /* blocksToSkip= */ 0);
}
@Override
@@ -1303,6 +1404,104 @@
@Override
public void sampleData(
ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
+ if (sampleDataPart == SAMPLE_DATA_PART_ENCRYPTION && !mInBandCryptoInfo) {
+ while (length > 0) {
+ switch (mEncryptionDataReadState) {
+ case STATE_READING_SIGNAL_BYTE:
+ int encryptionSignalByte = data.readUnsignedByte();
+ length--;
+ mHasSubsampleEncryptionData = ((encryptionSignalByte >> 7) & 1) != 0;
+ mEncryptionVectorSize = encryptionSignalByte & 0x7F;
+ mEncryptionDataSizeToSubtractFromSampleDataSize =
+ mEncryptionVectorSize + 1; // Signal byte.
+ mEncryptionDataReadState = STATE_READING_INIT_VECTOR;
+ break;
+ case STATE_READING_INIT_VECTOR:
+ Arrays.fill(mCryptoInfo.iv, (byte) 0); // Ensure 0-padding.
+ data.readBytes(mCryptoInfo.iv, /* offset= */ 0, mEncryptionVectorSize);
+ length -= mEncryptionVectorSize;
+ if (mHasSubsampleEncryptionData) {
+ mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE;
+ } else {
+ mCryptoInfo.numSubSamples = 0;
+ mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
+ }
+ break;
+ case STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE:
+ int numSubSamples = data.readUnsignedShort();
+ mCryptoInfo.numSubSamples = numSubSamples;
+ if (mCryptoInfo.numBytesOfClearData.length < numSubSamples) {
+ mCryptoInfo.numBytesOfClearData = new int[numSubSamples];
+ mCryptoInfo.numBytesOfEncryptedData = new int[numSubSamples];
+ }
+ length -= 2;
+ mEncryptionDataSizeToSubtractFromSampleDataSize +=
+ 2 + numSubSamples * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
+ mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_DATA;
+ break;
+ case STATE_READING_SUBSAMPLE_ENCRYPTION_DATA:
+ for (int i = 0; i < mCryptoInfo.numSubSamples; i++) {
+ mCryptoInfo.numBytesOfClearData[i] = data.readUnsignedShort();
+ mCryptoInfo.numBytesOfEncryptedData[i] = data.readInt();
+ }
+ length -=
+ mCryptoInfo.numSubSamples
+ * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
+ mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
+ if (length != 0) {
+ throw new IllegalStateException();
+ }
+ break;
+ default:
+ // Never happens.
+ throw new IllegalStateException();
+ }
+ }
+ } else if (sampleDataPart == SAMPLE_DATA_PART_SUPPLEMENTAL
+ && !mIncludeSupplementalData) {
+ mSkippedSupplementalDataBytes += length;
+ data.skipBytes(length);
+ } else {
+ outputSampleData(data, length);
+ }
+ }
+
+ @Override
+ public void sampleMetadata(
+ long timeUs, int flags, int size, int offset, @Nullable CryptoData cryptoData) {
+ size -= mSkippedSupplementalDataBytes;
+ mSkippedSupplementalDataBytes = 0;
+ mOutputConsumer.onSampleCompleted(
+ mTrackIndex,
+ timeUs,
+ getMediaParserFlags(flags),
+ size - mEncryptionDataSizeToSubtractFromSampleDataSize,
+ offset,
+ getPopulatedCryptoInfo(cryptoData));
+ mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
+ mEncryptionDataSizeToSubtractFromSampleDataSize = 0;
+ }
+
+ @Nullable
+ private CryptoInfo getPopulatedCryptoInfo(@Nullable CryptoData cryptoData) {
+ if (cryptoData == null) {
+ // The sample is not encrypted.
+ return null;
+ }
+ mCryptoInfo.key = cryptoData.encryptionKey;
+ // ExoPlayer modes match MediaCodec modes.
+ mCryptoInfo.mode = cryptoData.cryptoMode;
+ if (cryptoData.clearBlocks != 0) {
+ // Content is pattern-encrypted.
+ mCryptoInfo.setPattern(mEncryptionPattern);
+ mEncryptionPattern.set(cryptoData.encryptedBlocks, cryptoData.clearBlocks);
+ } else {
+ mCryptoInfo.setPattern(null);
+ }
+ return mCryptoInfo;
+ }
+
+ private void outputSampleData(ParsableByteArray data, int length) {
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
try {
mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchParsableByteArrayAdapter);
@@ -1311,13 +1510,6 @@
throw new RuntimeException(e);
}
}
-
- @Override
- public void sampleMetadata(
- long timeUs, int flags, int size, int offset, CryptoData encryptionData) {
- mOutputConsumer.onSampleCompleted(
- mTrackIndex, timeUs, flags, size, offset, toCryptoInfo(encryptionData));
- }
}
private static final class DataReaderAdapter implements InputReader {
@@ -1519,11 +1711,6 @@
}
}
- private static CryptoInfo toCryptoInfo(TrackOutput.CryptoData encryptionData) {
- // TODO: Implement.
- return null;
- }
-
/** Returns a new {@link SeekPoint} equivalent to the given {@code exoPlayerSeekPoint}. */
private static SeekPoint toSeekPoint(
com.google.android.exoplayer2.extractor.SeekPoint exoPlayerSeekPoint) {
@@ -1543,6 +1730,19 @@
}
}
+ private int getMediaParserFlags(int flags) {
+ @SampleFlags int result = 0;
+ result |= (flags & C.BUFFER_FLAG_ENCRYPTED) != 0 ? SAMPLE_FLAG_ENCRYPTED : 0;
+ result |= (flags & C.BUFFER_FLAG_KEY_FRAME) != 0 ? SAMPLE_FLAG_KEY_FRAME : 0;
+ result |= (flags & C.BUFFER_FLAG_DECODE_ONLY) != 0 ? SAMPLE_FLAG_DECODE_ONLY : 0;
+ result |=
+ (flags & C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA) != 0 && mIncludeSupplementalData
+ ? SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA
+ : 0;
+ result |= (flags & C.BUFFER_FLAG_LAST_SAMPLE) != 0 ? SAMPLE_FLAG_LAST_SAMPLE : 0;
+ return result;
+ }
+
@Nullable
private static Constructor<DrmInitData.SchemeInitData> getSchemeInitDataConstructor() {
// TODO: Use constructor statically when available.
@@ -1598,6 +1798,8 @@
expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM, Boolean.class);
expectedTypeByParameterName.put(PARAMETER_TS_DETECT_ACCESS_UNITS, Boolean.class);
expectedTypeByParameterName.put(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_IN_BAND_CRYPTO_INFO, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_INCLUDE_SUPPLEMENTAL_DATA, Boolean.class);
EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
}
}
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 3119b7d..68c27a8 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -55,6 +55,15 @@
"framework-module-stubs-defaults-publicapi",
"framework-permission-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-permission.api.public.latest",
+ removed_api_file: ":framework-permission-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-permission.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -63,6 +72,15 @@
"framework-module-stubs-defaults-systemapi",
"framework-permission-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-permission.api.system.latest",
+ removed_api_file: ":framework-permission-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-permission.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -71,6 +89,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-permission-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-permission.api.module-lib.latest",
+ removed_api_file: ":framework-permission-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-permission.api.module-lib.latest",
+ },
+ },
}
droidstubs {
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
index 2d92d00..6144976 100644
--- a/apex/permission/service/Android.bp
+++ b/apex/permission/service/Android.bp
@@ -41,6 +41,15 @@
name: "service-permission-stubs-srcs",
srcs: [ ":service-permission-sources" ],
defaults: ["service-module-stubs-srcs-defaults"],
+ check_api: {
+ last_released: {
+ api_file: ":service-permission.api.system-server.latest",
+ removed_api_file: ":service-permission-removed.api.system-server.latest",
+ },
+ api_lint: {
+ new_since: ":service-permission.api.system-server.latest",
+ },
+ },
visibility: ["//visibility:private"],
dist: { dest: "service-permission.txt" },
}
diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp
index dbb5bd3d..fdb078e 100644
--- a/apex/sdkextensions/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -39,7 +39,7 @@
sdk {
name: "sdkextensions-sdk",
- java_header_libs: [ "framework-sdkextensions-stubs-systemapi" ],
+ java_sdk_libs: [ "framework-sdkextensions" ],
}
apex_key {
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 6a78711..b8aad7d 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -25,14 +25,18 @@
visibility: [ "//frameworks/base" ] // For the "global" stubs.
}
-java_library {
+java_sdk_library {
name: "framework-sdkextensions",
srcs: [ ":framework-sdkextensions-sources" ],
- sdk_version: "system_current",
- libs: [ "framework-annotations-lib" ],
+ defaults: ["framework-module-defaults"],
+
+ // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
+ // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
+ // modules to java_sdk_library.
+ naming_scheme: "framework-modules",
+
permitted_packages: [ "android.os.ext" ],
installable: true,
- plugins: ["java_api_finder"],
visibility: [
"//frameworks/base/apex/sdkextensions",
"//frameworks/base/apex/sdkextensions/testing",
@@ -43,75 +47,3 @@
"test_com.android.sdkext",
],
}
-
-stubs_defaults {
- name: "framework-sdkextensions-stubs-defaults",
- srcs: [ ":framework-sdkextensions-sources" ],
- libs: [ "framework-annotations-lib" ],
- dist: { dest: "framework-sdkextensions.txt" },
-}
-
-droidstubs {
- name: "framework-sdkextensions-stubs-srcs-publicapi",
- defaults: [
- "framework-module-stubs-defaults-publicapi",
- "framework-sdkextensions-stubs-defaults",
- ],
-}
-
-droidstubs {
- name: "framework-sdkextensions-stubs-srcs-systemapi",
- defaults: [
- "framework-module-stubs-defaults-systemapi",
- "framework-sdkextensions-stubs-defaults",
- ],
-}
-
-droidstubs {
- name: "framework-sdkextensions-api-module_libs_api",
- defaults: [
- "framework-module-api-defaults-module_libs_api",
- "framework-sdkextensions-stubs-defaults",
- ],
-}
-
-droidstubs {
- name: "framework-sdkextensions-stubs-srcs-module_libs_api",
- defaults: [
- "framework-module-stubs-defaults-module_libs_api",
- "framework-sdkextensions-stubs-defaults",
- ],
-}
-
-java_library {
- name: "framework-sdkextensions-stubs-publicapi",
- srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
- defaults: ["framework-module-stubs-lib-defaults-publicapi"],
- visibility: [
- "//frameworks/base", // Framework
- "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ],
- dist: { dest: "framework-sdkextensions.jar" },
-}
-
-java_library {
- name: "framework-sdkextensions-stubs-systemapi",
- srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
- defaults: ["framework-module-stubs-lib-defaults-systemapi"],
- visibility: [
- "//frameworks/base", // Framework
- "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ],
- dist: { dest: "framework-sdkextensions.jar" },
-}
-
-java_library {
- name: "framework-sdkextensions-stubs-module_libs_api",
- srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
- defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
- visibility: [
- "//frameworks/base", // Framework
- "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ],
- dist: { dest: "framework-sdkextensions.jar" },
-}
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 7d0f2ee..9f5d933 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -93,6 +93,15 @@
"framework-module-stubs-defaults-publicapi",
"framework-statsd-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-statsd.api.public.latest",
+ removed_api_file: ":framework-statsd-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-statsd.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -101,6 +110,15 @@
"framework-module-stubs-defaults-systemapi",
"framework-statsd-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-statsd.api.system.latest",
+ removed_api_file: ":framework-statsd-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-statsd.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -109,6 +127,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-statsd-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-statsd.api.module-lib.latest",
+ removed_api_file: ":framework-statsd-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-statsd.api.module-lib.latest",
+ },
+ },
}
droidstubs {
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 7fbfc43..d1b7d8d 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -28,7 +28,6 @@
import android.os.IPullAtomCallback;
import android.os.IPullAtomResultReceiver;
import android.os.IStatsManagerService;
-import android.os.IStatsd;
import android.os.RemoteException;
import android.os.StatsFrameworkInitializer;
import android.util.AndroidException;
@@ -57,9 +56,6 @@
private final Context mContext;
@GuardedBy("sLock")
- private IStatsd mService;
-
- @GuardedBy("sLock")
private IStatsManagerService mStatsManagerService;
/**
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 93e6c10..5cf5e0b 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,11 +54,11 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Helper service for statsd (the native stats management service in cmds/statsd/).
@@ -112,17 +112,8 @@
private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
private final CompanionHandler mHandler;
- // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. This
- // and the flag mSentBootComplete below is used for synchronization to ensure that the boot
- // complete signal is only ever sent once to statsd. Two signals are needed because
- // #sayHiToStatsd can be called from both statsd and #onBootPhase
- // PHASE_THIRD_PARTY_APPS_CAN_START.
- @GuardedBy("sStatsdLock")
- private boolean mBootCompleted = false;
- // Flag that is set when IStatsd#bootCompleted is called. This flag ensures that boot complete
- // signal is only ever sent once.
- @GuardedBy("sStatsdLock")
- private boolean mSentBootComplete = false;
+ // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle.
+ private AtomicBoolean mBootCompleted = new AtomicBoolean(false);
public StatsCompanionService(Context context) {
super();
@@ -607,27 +598,35 @@
// Statsd related code
/**
- * Fetches the statsd IBinder service. This is a blocking call.
+ * Fetches the statsd IBinder service. This is a blocking call that always refetches statsd
+ * instead of returning the cached sStatsd.
* Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
* the cached sStatsd via {@link #getStatsdNonblocking()}.
*/
- private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
- .getStatsServiceManager()
- .getStatsdServiceRegisterer()
- .get());
- if (sStatsd != null) {
- try {
- sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
- statsdNotReadyLocked();
- }
+ private IStatsd fetchStatsdServiceLocked() {
+ sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
+ return sStatsd;
+ }
+
+ private void registerStatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
+ StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient(statsd, receivers);
+
+ try {
+ statsd.asBinder().linkToDeath(deathRecipient, /*flags=*/0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "linkToDeath (StatsdDeathRecipient) failed");
+ // Statsd has already died. Unregister receivers ourselves.
+ for (BroadcastReceiver receiver : receivers) {
+ mContext.unregisterReceiver(receiver);
+ }
+ synchronized (sStatsdLock) {
+ if (statsd == sStatsd) {
+ statsdNotReadyLocked();
}
}
- return sStatsd;
}
}
@@ -648,22 +647,23 @@
* statsd.
*/
private void sayHiToStatsd() {
- if (getStatsdNonblocking() != null) {
- Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
- new IllegalStateException(
- "sStatsd is not null when being fetched"));
- return;
+ IStatsd statsd;
+ synchronized (sStatsdLock) {
+ if (sStatsd != null && sStatsd.asBinder().isBinderAlive()) {
+ Log.e(TAG, "statsd has already been fetched before",
+ new IllegalStateException("IStatsd object should be null or dead"));
+ return;
+ }
+ statsd = fetchStatsdServiceLocked();
}
- StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
- IStatsd statsd = fetchStatsdService(deathRecipient);
+
if (statsd == null) {
- Log.i(TAG,
- "Could not yet find statsd to tell it that StatsCompanion is "
- + "alive.");
+ Log.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive.");
return;
}
- mStatsManagerService.statsdReady(statsd);
+
if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ mStatsManagerService.statsdReady(statsd);
try {
statsd.statsCompanionReady();
@@ -682,8 +682,7 @@
mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
// Setup receiver for user initialize (which happens once for a new user)
- // and
- // if a user is removed.
+ // and if a user is removed.
filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
@@ -691,27 +690,20 @@
// Setup receiver for device reboots or shutdowns.
filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverForAllUsers(
- shutdownEventReceiver, filter, null, null);
+ mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, null);
- // Only add the receivers if the registration is successful.
- deathRecipient.addRegisteredBroadcastReceivers(
- List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
+ // Register death recipient.
+ List<BroadcastReceiver> broadcastReceivers =
+ List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver);
+ registerStatsdDeathRecipient(statsd, broadcastReceivers);
- // Used so we can call statsd.bootComplete() outside of the lock.
- boolean shouldSendBootComplete = false;
- synchronized (sStatsdLock) {
- if (mBootCompleted && !mSentBootComplete) {
- mSentBootComplete = true;
- shouldSendBootComplete = true;
- }
- }
- if (shouldSendBootComplete) {
+ // Tell statsd that boot has completed. The signal may have already been sent, but since
+ // the signal-receiving function is idempotent, that's ok.
+ if (mBootCompleted.get()) {
statsd.bootCompleted();
}
- // Pull the latest state of UID->app name, version mapping when
- // statsd starts.
+ // Pull the latest state of UID->app name, version mapping when statsd starts.
informAllUids(mContext);
Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
@@ -722,18 +714,16 @@
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
- private List<BroadcastReceiver> mReceiversToUnregister;
+ private final IStatsd mStatsd;
+ private final List<BroadcastReceiver> mReceiversToUnregister;
- StatsdDeathRecipient() {
- mReceiversToUnregister = new ArrayList<>();
+ StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
+ mStatsd = statsd;
+ mReceiversToUnregister = receivers;
}
- public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
- synchronized (sStatsdLock) {
- mReceiversToUnregister.addAll(receivers);
- }
- }
-
+ // It is possible for binderDied to be called after a restarted statsd calls statsdReady,
+ // but that's alright because the code does not assume an ordering of the two calls.
@Override
public void binderDied() {
Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -762,13 +752,19 @@
}
}
}
- // We only unregister in binder death becaseu receivers can only be unregistered
- // once, or an IllegalArgumentException is thrown.
+
+ // Unregister receivers on death because receivers can only be unregistered once.
+ // Otherwise, an IllegalArgumentException is thrown.
for (BroadcastReceiver receiver: mReceiversToUnregister) {
mContext.unregisterReceiver(receiver);
}
- statsdNotReadyLocked();
- mSentBootComplete = false;
+
+ // It's possible for statsd to have restarted and called statsdReady, causing a new
+ // sStatsd binder object to be fetched, before the binderDied callback runs. Only
+ // call #statsdNotReadyLocked if that hasn't happened yet.
+ if (mStatsd == sStatsd) {
+ statsdNotReadyLocked();
+ }
}
}
}
@@ -779,19 +775,12 @@
}
void bootCompleted() {
+ mBootCompleted.set(true);
IStatsd statsd = getStatsdNonblocking();
- synchronized (sStatsdLock) {
- mBootCompleted = true;
- if (mSentBootComplete) {
- // do not send a boot complete a second time.
- return;
- }
- if (statsd == null) {
- // Statsd is not yet ready.
- // Delay the boot completed ping to {@link #sayHiToStatsd()}
- return;
- }
- mSentBootComplete = true;
+ if (statsd == null) {
+ // Statsd is not yet ready.
+ // Delay the boot completed ping to {@link #sayHiToStatsd()}
+ return;
}
try {
statsd.bootCompleted();
@@ -808,8 +797,7 @@
}
synchronized (sStatsdLock) {
- writer.println(
- "Number of configuration files deleted: " + mDeletedFiles.size());
+ writer.println("Number of configuration files deleted: " + mDeletedFiles.size());
if (mDeletedFiles.size() > 0) {
writer.println(" timestamp, deleted file name");
}
@@ -817,8 +805,7 @@
SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime();
for (Long elapsedMillis : mDeletedFiles.keySet()) {
long deletionMillis = lastBootMillis + elapsedMillis;
- writer.println(
- " " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
+ writer.println(" " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
}
}
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 90764b0..97846f2 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -172,6 +172,10 @@
public void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
int[] additiveFields, IPullAtomCallback pullerCallback) {
enforceRegisterStatsPullAtomPermission();
+ if (pullerCallback == null) {
+ Log.w(TAG, "Puller callback is null for atom " + atomTag);
+ return;
+ }
int callingUid = Binder.getCallingUid();
PullerKey key = new PullerKey(callingUid, atomTag);
PullerValue val =
diff --git a/api/current.txt b/api/current.txt
index 467aa32..952ccda 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12097,6 +12097,7 @@
field public static final String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
field public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
+ field public static final String FEATURE_CONTROLS = "android.software.controls";
field public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
field public static final String FEATURE_EMBEDDED = "android.hardware.type.embedded";
field public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
@@ -58326,9 +58327,9 @@
method public abstract void setAllowFileAccess(boolean);
method @Deprecated public abstract void setAllowFileAccessFromFileURLs(boolean);
method @Deprecated public abstract void setAllowUniversalAccessFromFileURLs(boolean);
- method public abstract void setAppCacheEnabled(boolean);
+ method @Deprecated public abstract void setAppCacheEnabled(boolean);
method @Deprecated public abstract void setAppCacheMaxSize(long);
- method public abstract void setAppCachePath(String);
+ method @Deprecated public abstract void setAppCachePath(String);
method public abstract void setBlockNetworkImage(boolean);
method public abstract void setBlockNetworkLoads(boolean);
method public abstract void setBuiltInZoomControls(boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index cc3604c..5dc7bdb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -431,6 +431,7 @@
}
public class DreamManager {
+ method @RequiresPermission("android.permission.READ_DREAM_STATE") public boolean isDreaming();
method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void setActiveDream(@NonNull android.content.ComponentName);
method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void startDream(@NonNull android.content.ComponentName);
method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void stopDream();
@@ -1810,6 +1811,7 @@
}
public class ConnectivityManager {
+ method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a1278f3..ecb95bd 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1306,7 +1306,7 @@
if (mSystemWd < 0) {
close(mInotifyFd);
mInotifyFd = -1;
- SLOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
+ SLOGE("Could not add watch for %s: %s", SYSTEM_DATA_DIR_PATH, strerror(errno));
return NO_INIT;
}
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 9e6d0a2..dc16125 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -351,9 +351,9 @@
Status IncidentService::registerSection(const int id, const String16& name16,
const sp<IIncidentDumpCallback>& callback) {
- const char* name = String8(name16).c_str();
+ const String8 name = String8(name16);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- ALOGI("Uid %d registers section %d '%s'", callingUid, id, name);
+ ALOGI("Uid %d registers section %d '%s'", callingUid, id, name.c_str());
if (callback == nullptr) {
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
@@ -363,11 +363,11 @@
ALOGW("Error registering section %d: calling uid does not match", id);
return Status::fromExceptionCode(Status::EX_SECURITY);
}
- mRegisteredSections.at(i) = new BringYourOwnSection(id, name, callingUid, callback);
+ mRegisteredSections.at(i) = new BringYourOwnSection(id, name.c_str(), callingUid, callback);
return Status::ok();
}
}
- mRegisteredSections.push_back(new BringYourOwnSection(id, name, callingUid, callback));
+ mRegisteredSections.push_back(new BringYourOwnSection(id, name.c_str(), callingUid, callback));
return Status::ok();
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 114cbb8..61e5eb0 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -876,7 +876,9 @@
status_t BringYourOwnSection::BlockingCall(unique_fd& pipeWriteFd) const {
android::os::ParcelFileDescriptor pfd(std::move(pipeWriteFd));
- mCallback->onDumpSection(pfd);
+ if(mCallback != nullptr) {
+ mCallback->onDumpSection(pfd);
+ }
return NO_ERROR;
}
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 2ce45ed..bc4909d 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -207,7 +207,7 @@
virtual status_t BlockingCall(unique_fd& pipeWriteFd) const;
private:
- const sp<IIncidentDumpCallback>& mCallback;
+ const sp<IIncidentDumpCallback> mCallback;
};
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index bd9f7a5..4ffa040 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -343,9 +343,11 @@
if (!utf8Args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, utf8Args);
}
+
if (!utf8Args[0].compare(String8("send-active-configs"))) {
return cmd_trigger_active_config_broadcast(out, utf8Args);
}
+
if (!utf8Args[0].compare(String8("data-subscribe"))) {
{
std::lock_guard<std::mutex> lock(mShellSubscriberMutex);
@@ -824,7 +826,7 @@
uids.push_back(AID_SYSTEM);
}
vector<shared_ptr<LogEvent>> stats;
- if (mPullerManager->Pull(s, uids, &stats)) {
+ if (mPullerManager->Pull(s, uids, getElapsedRealtimeNs(), &stats)) {
for (const auto& it : stats) {
dprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b79406c..1f505b9 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -428,6 +428,18 @@
266 [(module) = "framework"];
AccessibilityServiceReported accessibility_service_reported = 267 [(module) = "settings"];
DocsUIDragAndDropReported docs_ui_drag_and_drop_reported = 268 [(module) = "docsui"];
+ AppUsageEventOccurred app_usage_event_occurred = 269 [(module) = "framework"];
+ AutoRevokeNotificationClicked auto_revoke_notification_clicked =
+ 270 [(module) = "permissioncontroller"];
+ AutoRevokeFragmentAppViewed auto_revoke_fragment_app_viewed =
+ 271 [(module) = "permissioncontroller"];
+ AutoRevokedAppInteraction auto_revoked_app_interaction =
+ 272 [(module) = "permissioncontroller", (module) = "settings"];
+ AppPermissionGroupsFragmentAutoRevokeAction
+ app_permission_groups_fragment_auto_revoke_action =
+ 273 [(module) = "permissioncontroller"];
+ EvsUsageStatsReported evs_usage_stats_reported = 274 [(module) = "evs"];
+ AudioPowerUsageDataReported audio_power_usage_data_reported = 275;
SdkExtensionStatus sdk_extension_status = 354;
// StatsdStats tracks platform atoms with ids upto 500.
@@ -435,7 +447,7 @@
}
// Pulled events will start at field 10000.
- // Next: 10080
+ // Next: 10084
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -526,6 +538,10 @@
SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
+ DisplayWakeReason display_wake_reason = 10081 [(module) = "framework"];
+ DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"];
+ BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
+ 10083 [(module) = "framework"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -1244,7 +1260,8 @@
*/
message ChargingStateChanged {
// State of the battery, from frameworks/base/core/proto/android/os/enums.proto.
- optional android.os.BatteryStatusEnum state = 1;
+ optional android.os.BatteryStatusEnum state = 1
+ [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
}
/**
@@ -3021,14 +3038,14 @@
optional string component_name = 11;
// (x, y) coordinate and the index information of the target on the container
- optional int32 grid_x = 12;
- optional int32 grid_y = 13;
- optional int32 page_id = 14;
+ optional int32 grid_x = 12 [default = -1];
+ optional int32 grid_y = 13 [default = -1];
+ optional int32 page_id = 14 [default = -2];
// e.g., folder icon's (x, y) location and index information on the workspace
- optional int32 grid_x_parent = 15;
- optional int32 grid_y_parent = 16;
- optional int32 page_id_parent = 17;
+ optional int32 grid_x_parent = 15 [default = -1];
+ optional int32 grid_y_parent = 16 [default = -1];
+ optional int32 page_id_parent = 17 [default = -2];
// e.g., SEARCHBOX_ALLAPPS, FOLDER_WORKSPACE
optional int32 hierarchy = 18;
@@ -3036,7 +3053,7 @@
optional bool is_work_profile = 19;
// Used to store the predicted rank of the target
- optional int32 rank = 20;
+ optional int32 rank = 20 [default = -1];
// e.g., folderLabelState can be captured in the following two fields
optional int32 from_state = 21;
@@ -3044,6 +3061,9 @@
// e.g., autofilled or suggested texts that are not user entered
optional string edittext = 23;
+
+ // e.g., number of contents inside a container (e.g., icons inside a folder)
+ optional int32 cardinality = 24;
}
/**
@@ -3064,22 +3084,34 @@
optional string component_name = 6;
// (x, y) coordinate and the index information of the target on the container
- optional int32 grid_x = 7;
- optional int32 grid_y = 8;
- optional int32 page_id = 9;
+ optional int32 grid_x = 7 [default = -1];
+ optional int32 grid_y = 8 [default = -1];
+ optional int32 page_id = 9 [default = -2];
// e.g., folder icon's (x, y) location and index information on the workspace
- optional int32 grid_x_parent = 10;
- optional int32 grid_y_parent = 11;
- optional int32 page_id_parent = 12;
+ // e.g., when used with widgets target, use these values for (span_x, span_y)
+ optional int32 grid_x_parent = 10 [default = -1];
+ optional int32 grid_y_parent = 11 [default = -1];
+ optional int32 page_id_parent = 12 [default = -2];
- // e.g., WORKSPACE, HOTSEAT, FOLDER_WORKSPACE, FOLDER_HOTSEAT
+ // UNKNOWN = 0
+ // HOTSEAT = 1
+ // WORKSPACE = 2
+ // FOLDER_HOTSEAT = 3
+ // FOLDER_WORKSPACE = 4
optional int32 hierarchy = 13;
optional bool is_work_profile = 14;
// e.g., PIN, WIDGET TRAY, APPS TRAY, PREDICTION
optional int32 origin = 15;
+
+ // e.g., number of icons inside a folder
+ optional int32 cardinality = 16;
+
+ // e.g., (x, y) span of the widget inside homescreen grid system
+ optional int32 span_x = 17 [default = 1];
+ optional int32 span_y = 18 [default = 1];
}
/**
@@ -4911,6 +4943,52 @@
}
/**
+ * Used for pull network statistics via mobile|wifi networks, and sliced by interesting dimensions.
+ * Note that data is expected to be sliced into more dimensions in future. In other words,
+ * the caller must not assume the data is unique when filtering with a set of matching conditions.
+ * Thus, as the dimension grows, the caller will not be affected.
+ *
+ * Pulled from:
+ * StatsPullAtomService (using NetworkStatsService to get NetworkStats)
+ */
+message DataUsageBytesTransfer {
+ // State of this record. Should be NetworkStats#SET_DEFAULT or NetworkStats#SET_FOREGROUND to
+ // indicate the foreground state, or NetworkStats#SET_ALL to indicate the record is for all
+ // states combined, not including debug states. See NetworkStats#SET_*.
+ optional int32 state = 1;
+
+ optional int64 rx_bytes = 2;
+
+ optional int64 rx_packets = 3;
+
+ optional int64 tx_bytes = 4;
+
+ optional int64 tx_packets = 5;
+
+ // Radio Access Technology (RAT) type of this record, should be one of
+ // TelephonyManager#NETWORK_TYPE_* constants, or NetworkTemplate#NETWORK_TYPE_ALL to indicate
+ // the record is for all rat types combined.
+ optional int32 rat_type = 6;
+
+ // Mcc/Mnc read from sim if the record is for a specific subscription, null indicates the
+ // record is combined regardless of subscription.
+ optional string sim_mcc = 7;
+ optional string sim_mnc = 8;
+
+ // Enumeration of opportunistic states with an additional ALL state indicates the record is
+ // combined regardless of the boolean value in its field.
+ enum DataSubscriptionState {
+ ALL = 1;
+ OPPORTUNISTIC = 2;
+ NOT_OPPORTUNISTIC = 3;
+ }
+ // Mark whether the subscription is an opportunistic data subscription, and ALL indicates the
+ // record is combined regardless of opportunistic data subscription.
+ // See {@link SubscriptionManager#setOpportunistic}.
+ optional DataSubscriptionState opportunistic_data_sub = 9;
+}
+
+/**
* Pulls bytes transferred via bluetooth. It is pulled from Bluetooth controller.
*
* Pulled from:
@@ -8194,7 +8272,8 @@
}
/**
-* Information about a AppPermissionsFragment viewed by user
+* Information about a AppPermissionGroupsFragment viewed by user. Fragment has been renamed, but
+* the log retains the old fragment name.
*/
message AppPermissionsFragmentViewed {
// id which identifies single session of user interacting with permission controller
@@ -8222,7 +8301,6 @@
}
optional Category category = 6;
}
-
/**
* Information about a PermissionAppsFragment viewed by user.
* Logged from ui/handheld/PermissionAppsFragment.java
@@ -8255,6 +8333,99 @@
}
/**
+* Log that the Auto Revoke notification has been clicked
+* Logged from ui/ManagePermissionsActivity
+*/
+message AutoRevokeNotificationClicked {
+ // id which identifies single session of user interacting with permission controller
+ optional int64 session_id = 1;
+}
+
+/**
+* Log that an app has been displayed on the auto revoke page, and lists one permission that was
+* auto revoked for it.
+* Logged from ui/handheld/AutoRevokeFragment
+*/
+message AutoRevokeFragmentAppViewed {
+ // id which identifies single session of user interacting with permission controller
+ optional int64 session_id = 1;
+
+ // UID of package for which permissions are viewed
+ optional int32 uid = 2 [(is_uid) = true];
+
+ // Name of package for which permissions are viewed
+ optional string package_name = 3;
+
+ // The name of a permission group that has been revoked
+ optional string permission_group_name = 4;
+
+ // The age of the app- more than three months old, or more than six months
+ enum Age {
+ UNDEFINED = 0;
+ NEWER_BUCKET = 1;
+ OLDER_BUCKET = 2;
+ }
+
+ // How long the app has been unused. Currently, newer bucket is 3 months, older is 6 months
+ optional Age age = 5;
+}
+
+/**
+* Log that the user has interacted with an app on the auto revoke fragment
+* Logged from ui/handheld/AutoRevokeFragment
+*/
+message AutoRevokedAppInteraction {
+ // id which identifies single session of user interacting with permission controller
+ optional int64 session_id = 1;
+
+ // UID of package for which permissions are viewed
+ optional int32 uid = 2 [(is_uid) = true];
+
+ // Name of package for which permissions are viewed
+ optional string package_name = 3;
+
+ enum Action {
+ UNDEFINED = 0;
+ REMOVE = 1;
+ OPEN = 2;
+ APP_INFO = 3;
+ PERMISSIONS = 4;
+ REMOVE_IN_SETTINGS = 5;
+ OPEN_IN_SETTINGS = 6;
+ }
+
+ // The action the user took to interact with the app
+ optional Action action = 4;
+}
+
+/**
+* Log that the AppPermissionGroupsFragment has been interacted with for the possible purposes of
+* auto revoke, or that the auto revoke switch has been changed
+* Logged from ui/handheld/AppPermissionGroupsFragment
+ */
+message AppPermissionGroupsFragmentAutoRevokeAction {
+ // id which identifies single session of user interacting with permission controller
+ optional int64 session_id = 1;
+
+ // UID of package for which permissions are viewed
+ optional int32 uid = 2 [(is_uid) = true];
+
+ // Name of package for which permissions are viewed
+ optional string package_name = 3;
+
+ enum Action {
+ UNDEFINED = 0;
+ OPENED_FOR_AUTO_REVOKE = 1;
+ OPENED_FROM_INTENT = 2;
+ SWITCH_ENABLED = 3;
+ SWITCH_DISABLED = 4;
+ }
+
+ // The action the user took to interact with the fragment
+ optional Action action = 4;
+}
+
+/**
* Logs when there is a smart selection related event.
* See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
* Logged from: TextClassifierEventLogger.java
@@ -9111,6 +9282,9 @@
// Whether the call was performed while roaming.
optional bool is_roaming = 24;
+
+ // A random number used as the dimension field to pull multiple atoms.
+ optional int32 dimension = 25;
}
/**
@@ -9337,9 +9511,6 @@
/** The ID of the entry that the users actioned on */
optional android.app.tvsettings.ItemId item_id = 2;
-
- /** Additional information (e.g., navigation direction on page focused) */
- optional string additional_info = 3;
}
/**
@@ -9510,3 +9681,149 @@
// From frameworks/base/core/proto/android/stats/accessibility/accessibility_enums.proto.
optional android.stats.accessibility.ServiceStatus service_status = 2;
}
+
+message DisplayWakeReason {
+ // Wake_up_reason code
+ // If LOWORD(wake_up_reason) = 0
+ // reference to HIWORD(wake_up_reason) PowerManager.WAKE_REASON_XXX
+ // else reference wake_up_reason to
+ // frameworks/base/services/core/java/com/android/server/power/Notifier.java#DispWakeupReason
+ optional int32 wake_up_reason = 1;
+ // Count of wake up by reason
+ optional int32 wake_times = 2;
+}
+
+/**
+ * Logs app usage events.
+ */
+message AppUsageEventOccurred {
+ optional int32 uid = 1 [(is_uid) = true];
+ optional string package_name = 2;
+ optional string class_name = 3;
+
+ enum EventType {
+ NONE = 0;
+ MOVE_TO_FOREGROUND = 1;
+ MOVE_TO_BACKGROUND = 2;
+ }
+ optional EventType event_type = 4;
+}
+
+/*
+ * Quality metrics logged when EVS cameras are active.
+ *
+ * Logged from:
+ * packages/services/Car/evs/manager/1.1/Enumerator.cpp
+ */
+message EvsUsageStatsReported {
+
+ // Camera identifier to distinguish the source camera device. This is not
+ // globally unique and therefore cannot be used to identify the user and/or
+ // the device.
+ optional int32 device_id = 1;
+
+ // Peak number of clients during the service
+ optional int32 peak_num_clients = 2;
+
+ // Number of erroneous events during the service
+ optional int32 num_errors = 3;
+
+ // Round trip latency of the very first frame
+ optional int64 first_latency_millis = 4;
+
+ // Average frame round trip latency
+ optional float avg_latency_millis = 5;
+
+ // Peak frame round trip latency
+ optional int64 peak_latency_millis = 6;
+
+ // Total number of frames received
+ optional int64 total_frames = 7;
+
+ // Number of frames ignored
+ optional int64 ignored_frames = 8;
+
+ // Number of dropped frames to synchronize camera devices
+ optional int64 dropped_frames_to_sync = 9;
+
+ // The duration of the service
+ optional int64 duration_millis = 10;
+}
+
+/**
+ * Logs audio power usage stats.
+ *
+ * Pushed from:
+ * frameworks/av/services/mediametrics/AudioPowerUsage.cpp
+ */
+message AudioPowerUsageDataReported {
+ /**
+ * Device used for input/output
+ *
+ * All audio devices please refer to below file:
+ * system/media/audio/include/system/audio-base.h
+ *
+ * Define our own enum values because we don't report all audio devices.
+ * Currently, we only report built-in audio devices such as handset, speaker,
+ * built-in mics, common audio devices such as wired headset, usb headset
+ * and bluetooth devices.
+ */
+ enum AudioDevice {
+ OUTPUT_EARPIECE = 0x1; // handset
+ OUTPUT_SPEAKER = 0x2; // dual speaker
+ OUTPUT_WIRED_HEADSET = 0x4; // 3.5mm headset
+ OUTPUT_USB_HEADSET = 0x8; // usb headset
+ OUTPUT_BLUETOOTH_SCO = 0x10; // bluetooth sco
+ OUTPUT_BLUETOOTH_A2DP = 0x20; // a2dp
+ OUTPUT_SPEAKER_SAFE = 0x40; // bottom speaker
+
+ INPUT_DEVICE_BIT = 0x40000000; // non-negative positive int32.
+ INPUT_BUILTIN_MIC = 0x40000001; // buildin mic
+ INPUT_BUILTIN_BACK_MIC = 0x40000002; // buildin back mic
+ INPUT_WIRED_HEADSET_MIC = 0x40000004; // 3.5mm headset mic
+ INPUT_USB_HEADSET_MIC = 0x40000008; // usb headset mic
+ INPUT_BLUETOOTH_SCO = 0x40000010; // bluetooth sco mic
+ }
+ optional AudioDevice audio_device = 1;
+
+ // Duration of the audio in seconds
+ optional int32 duration_secs = 2;
+
+ // Average volume (0 ... 1.0)
+ optional float average_volume = 3;
+
+ enum AudioType {
+ UNKNOWN_TYPE = 0;
+ VOICE_CALL_TYPE = 1; // voice call
+ VOIP_CALL_TYPE = 2; // voip call, including uplink and downlink
+ MEDIA_TYPE = 3; // music and system sound
+ RINGTONE_NOTIFICATION_TYPE = 4; // ringtone and notification
+ ALARM_TYPE = 5; // alarm type
+ // record type
+ CAMCORDER_TYPE = 6; // camcorder
+ RECORD_TYPE = 7; // other recording
+ }
+ optional AudioType type = 4;
+}
+
+/**
+ * Pulls bytes transferred over WiFi and mobile networks sliced by uid, is_metered, and tag.
+ *
+ * Pulled from:
+ * StatsPullAtomService, which uses NetworkStatsService to query NetworkStats.
+ */
+message BytesTransferByTagAndMetered {
+ optional int32 uid = 1 [(is_uid) = true];
+
+ optional bool is_metered = 2;
+
+ optional int32 tag = 3;
+
+ optional int64 rx_bytes = 4;
+
+ optional int64 rx_packets = 5;
+
+ optional int64 tx_bytes = 6;
+
+ optional int64 tx_packets = 7;
+}
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
index 3618bb0..78e6f09 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -86,6 +86,7 @@
// in unit tests. In process calls are not oneway.
Status status = mCallback->onPullAtom(mTagId, resultReceiver);
if (!status.isOk()) {
+ StatsdStats::getInstance().notePullBinderCallFailed(mTagId);
return false;
}
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 5192ddf..9df4d1f 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -38,14 +38,16 @@
mPullTimeoutNs(pullTimeoutNs),
mCoolDownNs(coolDownNs),
mAdditiveFields(additiveFields),
- mLastPullTimeNs(0) {
+ mLastPullTimeNs(0),
+ mLastEventTimeNs(0) {
}
-bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
+bool StatsPuller::Pull(const int64_t eventTimeNs, std::vector<std::shared_ptr<LogEvent>>* data) {
lock_guard<std::mutex> lock(mLock);
int64_t elapsedTimeNs = getElapsedRealtimeNs();
StatsdStats::getInstance().notePull(mTagId);
- const bool shouldUseCache = elapsedTimeNs - mLastPullTimeNs < mCoolDownNs;
+ const bool shouldUseCache =
+ (mLastEventTimeNs == eventTimeNs) || (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs);
if (shouldUseCache) {
if (mHasGoodData) {
(*data) = mCachedData;
@@ -54,13 +56,13 @@
}
return mHasGoodData;
}
-
if (mLastPullTimeNs > 0) {
StatsdStats::getInstance().updateMinPullIntervalSec(
mTagId, (elapsedTimeNs - mLastPullTimeNs) / NS_PER_SEC);
}
mCachedData.clear();
mLastPullTimeNs = elapsedTimeNs;
+ mLastEventTimeNs = eventTimeNs;
mHasGoodData = PullInternal(&mCachedData);
if (!mHasGoodData) {
return mHasGoodData;
@@ -70,7 +72,7 @@
const bool pullTimeOut = pullDurationNs > mPullTimeoutNs;
if (pullTimeOut) {
// Something went wrong. Discard the data.
- clearCacheLocked();
+ mCachedData.clear();
mHasGoodData = false;
StatsdStats::getInstance().notePullTimeout(mTagId);
ALOGW("Pull for atom %d exceeds timeout %lld nano seconds.", mTagId,
@@ -82,6 +84,11 @@
mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId, mAdditiveFields);
}
+ if (mCachedData.empty()) {
+ VLOG("Data pulled is empty");
+ StatsdStats::getInstance().noteEmptyData(mTagId);
+ }
+
(*data) = mCachedData;
return mHasGoodData;
}
@@ -99,6 +106,7 @@
int ret = mCachedData.size();
mCachedData.clear();
mLastPullTimeNs = 0;
+ mLastEventTimeNs = 0;
return ret;
}
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index fee571c..470d15e 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -51,7 +51,7 @@
// 2) pull takes longer than mPullTimeoutNs (intrinsic to puller)
// If a metric wants to make any change to the data, like timestamps, it
// should make a copy as this data may be shared with multiple metrics.
- bool Pull(std::vector<std::shared_ptr<LogEvent>>* data);
+ bool Pull(const int64_t eventTimeNs, std::vector<std::shared_ptr<LogEvent>>* data);
// Clear cache immediately
int ForceClearCache();
@@ -94,6 +94,11 @@
int64_t mLastPullTimeNs;
+ // All pulls happen due to an event (app upgrade, bucket boundary, condition change, etc).
+ // If multiple pulls need to be done at the same event time, we will always use the cache after
+ // the first pull.
+ int64_t mLastEventTimeNs;
+
// Cache of data from last pull. If next request comes before cool down finishes,
// cached data will be returned.
// Cached data is cleared when
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index cfd5d14..8a9ec74 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -91,48 +91,52 @@
mPullAtomCallbackDeathRecipient(AIBinder_DeathRecipient_new(pullAtomCallbackDied)) {
}
-bool StatsPullerManager::Pull(int tagId, const ConfigKey& configKey,
+bool StatsPullerManager::Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
vector<shared_ptr<LogEvent>>* data, bool useUids) {
std::lock_guard<std::mutex> _l(mLock);
- return PullLocked(tagId, configKey, data, useUids);
+ return PullLocked(tagId, configKey, eventTimeNs, data, useUids);
}
-bool StatsPullerManager::Pull(int tagId, const vector<int32_t>& uids,
+bool StatsPullerManager::Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool useUids) {
std::lock_guard<std::mutex> _l(mLock);
- return PullLocked(tagId, uids, data, useUids);
+ return PullLocked(tagId, uids, eventTimeNs, data, useUids);
}
bool StatsPullerManager::PullLocked(int tagId, const ConfigKey& configKey,
- vector<shared_ptr<LogEvent>>* data, bool useUids) {
+ const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data,
+ bool useUids) {
vector<int32_t> uids;
if (useUids) {
auto uidProviderIt = mPullUidProviders.find(configKey);
if (uidProviderIt == mPullUidProviders.end()) {
ALOGE("Error pulling tag %d. No pull uid provider for config key %s", tagId,
configKey.ToString().c_str());
+ StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
return false;
}
sp<PullUidProvider> pullUidProvider = uidProviderIt->second.promote();
if (pullUidProvider == nullptr) {
ALOGE("Error pulling tag %d, pull uid provider for config %s is gone.", tagId,
configKey.ToString().c_str());
+ StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
return false;
}
uids = pullUidProvider->getPullAtomUids(tagId);
}
- return PullLocked(tagId, uids, data, useUids);
+ return PullLocked(tagId, uids, eventTimeNs, data, useUids);
}
bool StatsPullerManager::PullLocked(int tagId, const vector<int32_t>& uids,
- vector<shared_ptr<LogEvent>>* data, bool useUids) {
+ const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data,
+ bool useUids) {
VLOG("Initiating pulling %d", tagId);
if (useUids) {
for (int32_t uid : uids) {
PullerKey key = {.atomTag = tagId, .uid = uid};
auto pullerIt = kAllPullAtomInfo.find(key);
if (pullerIt != kAllPullAtomInfo.end()) {
- bool ret = pullerIt->second->Pull(data);
+ bool ret = pullerIt->second->Pull(eventTimeNs, data);
VLOG("pulled %zu items", data->size());
if (!ret) {
StatsdStats::getInstance().notePullFailed(tagId);
@@ -140,13 +144,14 @@
return ret;
}
}
+ StatsdStats::getInstance().notePullerNotFound(tagId);
ALOGW("StatsPullerManager: Unknown tagId %d", tagId);
return false; // Return early since we don't know what to pull.
} else {
PullerKey key = {.atomTag = tagId, .uid = -1};
auto pullerIt = kAllPullAtomInfo.find(key);
if (pullerIt != kAllPullAtomInfo.end()) {
- bool ret = pullerIt->second->Pull(data);
+ bool ret = pullerIt->second->Pull(eventTimeNs, data);
VLOG("pulled %zu items", data->size());
if (!ret) {
StatsdStats::getInstance().notePullFailed(tagId);
@@ -287,11 +292,9 @@
}
for (const auto& pullInfo : needToPull) {
vector<shared_ptr<LogEvent>> data;
- bool pullSuccess = PullLocked(pullInfo.first->atomTag, pullInfo.first->configKey, &data);
- if (pullSuccess) {
- StatsdStats::getInstance().notePullDelay(pullInfo.first->atomTag,
- getElapsedRealtimeNs() - elapsedTimeNs);
- } else {
+ bool pullSuccess = PullLocked(pullInfo.first->atomTag, pullInfo.first->configKey,
+ elapsedTimeNs, &data);
+ if (!pullSuccess) {
VLOG("pull failed at %lld, will try again later", (long long)elapsedTimeNs);
}
@@ -354,6 +357,11 @@
std::lock_guard<std::mutex> _l(mLock);
VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
+ if (callback == nullptr) {
+ ALOGW("SetPullAtomCallback called with null callback for atom %d.", atomTag);
+ return;
+ }
+
StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
int64_t actualCoolDownNs = coolDownNs < kMinCoolDownNs ? kMinCoolDownNs : coolDownNs;
int64_t actualTimeoutNs = timeoutNs > kMaxTimeoutNs ? kMaxTimeoutNs : timeoutNs;
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 5e18aaa..194a0f5 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -101,11 +101,11 @@
// registered for any of the uids for this atom.
// If the metric wants to make any change to the data, like timestamps, they
// should make a copy as this data may be shared with multiple metrics.
- virtual bool Pull(int tagId, const ConfigKey& configKey,
+ virtual bool Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool useUids = true);
// Same as above, but directly specify the allowed uids to pull from.
- virtual bool Pull(int tagId, const vector<int32_t>& uids,
+ virtual bool Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool useUids = true);
// Clear pull data cache immediately.
@@ -152,11 +152,11 @@
// mapping from Config Key to the PullUidProvider for that config
std::map<ConfigKey, wp<PullUidProvider>> mPullUidProviders;
- bool PullLocked(int tagId, const ConfigKey& configKey, vector<std::shared_ptr<LogEvent>>* data,
- bool useUids = true);
+ bool PullLocked(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool useUids = true);
- bool PullLocked(int tagId, const vector<int32_t>& uids, vector<std::shared_ptr<LogEvent>>* data,
- bool useUids);
+ bool PullLocked(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool useUids);
// locks for data receiver and StatsCompanionService changes
std::mutex mLock;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 46f5dbd..c027fff 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -472,14 +472,19 @@
mPulledAtomStats[atomId].pullFailed++;
}
-void StatsdStats::noteStatsCompanionPullFailed(int atomId) {
+void StatsdStats::notePullUidProviderNotFound(int atomId) {
lock_guard<std::mutex> lock(mLock);
- mPulledAtomStats[atomId].statsCompanionPullFailed++;
+ mPulledAtomStats[atomId].pullUidProviderNotFound++;
}
-void StatsdStats::noteStatsCompanionPullBinderTransactionFailed(int atomId) {
+void StatsdStats::notePullerNotFound(int atomId) {
lock_guard<std::mutex> lock(mLock);
- mPulledAtomStats[atomId].statsCompanionPullBinderTransactionFailed++;
+ mPulledAtomStats[atomId].pullerNotFound++;
+}
+
+void StatsdStats::notePullBinderCallFailed(int atomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[atomId].binderCallFailCount++;
}
void StatsdStats::noteEmptyData(int atomId) {
@@ -608,6 +613,7 @@
for (auto& pullStats : mPulledAtomStats) {
pullStats.second.totalPull = 0;
pullStats.second.totalPullFromCache = 0;
+ pullStats.second.minPullIntervalSec = LONG_MAX;
pullStats.second.avgPullTimeNs = 0;
pullStats.second.maxPullTimeNs = 0;
pullStats.second.numPullTime = 0;
@@ -617,9 +623,13 @@
pullStats.second.dataError = 0;
pullStats.second.pullTimeout = 0;
pullStats.second.pullExceedMaxDelay = 0;
+ pullStats.second.pullFailed = 0;
+ pullStats.second.pullUidProviderNotFound = 0;
+ pullStats.second.pullerNotFound = 0;
pullStats.second.registeredCount = 0;
pullStats.second.unregisteredCount = 0;
pullStats.second.atomErrorCount = 0;
+ pullStats.second.binderCallFailCount = 0;
}
mAtomMetricStats.clear();
mActivationBroadcastGuardrailStats.clear();
@@ -764,14 +774,16 @@
" (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay "
"nanos)%lld, "
" (max pull delay nanos)%lld, (data error)%ld\n"
- " (pull timeout)%ld, (pull exceed max delay)%ld\n"
- " (registered count) %ld, (unregistered count) %ld\n"
+ " (pull timeout)%ld, (pull exceed max delay)%ld"
+ " (no uid provider count)%ld, (no puller found count)%ld\n"
+ " (registered count) %ld, (unregistered count) %ld"
" (atom error count) %d\n",
(int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
(long)pair.second.pullFailed, (long)pair.second.minPullIntervalSec,
(long long)pair.second.avgPullTimeNs, (long long)pair.second.maxPullTimeNs,
(long long)pair.second.avgPullDelayNs, (long long)pair.second.maxPullDelayNs,
pair.second.dataError, pair.second.pullTimeout, pair.second.pullExceedMaxDelay,
+ pair.second.pullUidProviderNotFound, pair.second.pullerNotFound,
pair.second.registeredCount, pair.second.unregisteredCount,
pair.second.atomErrorCount);
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 805281c..3d0eeb8 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -371,21 +371,30 @@
int32_t lastAtomTag, int32_t uid, int32_t pid);
/**
- * Records that the pull of an atom has failed
+ * Records that the pull of an atom has failed. Eg, if the client indicated the pull failed, if
+ * the pull timed out, or if the outgoing binder call failed.
+ * This count will only increment if the puller was actually invoked.
+ *
+ * It does not include a pull not occurring due to not finding the appropriate
+ * puller. These cases are covered in other counts.
*/
void notePullFailed(int atomId);
/**
- * Records that the pull of StatsCompanionService atom has failed
+ * Records that the pull of an atom has failed due to not having a uid provider.
*/
- void noteStatsCompanionPullFailed(int atomId);
+ void notePullUidProviderNotFound(int atomId);
/**
- * Records that the pull of a StatsCompanionService atom has failed due to a failed binder
- * transaction. This can happen when StatsCompanionService returns too
- * much data (the max Binder parcel size is 1MB)
+ * Records that the pull of an atom has failed due not finding a puller registered by a
+ * trusted uid.
*/
- void noteStatsCompanionPullBinderTransactionFailed(int atomId);
+ void notePullerNotFound(int atomId);
+
+ /**
+ * Records that the pull has failed due to the outgoing binder call failing.
+ */
+ void notePullBinderCallFailed(int atomId);
/**
* A pull with no data occurred
@@ -503,12 +512,13 @@
long pullTimeout = 0;
long pullExceedMaxDelay = 0;
long pullFailed = 0;
- long statsCompanionPullFailed = 0;
- long statsCompanionPullBinderTransactionFailed = 0;
+ long pullUidProviderNotFound = 0;
+ long pullerNotFound = 0;
long emptyData = 0;
long registeredCount = 0;
long unregisteredCount = 0;
int32_t atomErrorCount = 0;
+ long binderCallFailCount = 0;
} PulledAtomStats;
typedef struct {
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 8ec0173..f56fa62 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -66,15 +66,6 @@
#define ATTRIBUTION_CHAIN_TYPE 0x09
#define ERROR_TYPE 0x0F
-LogEvent::LogEvent(const LogEvent& event) {
- mTagId = event.mTagId;
- mLogUid = event.mLogUid;
- mLogPid = event.mLogPid;
- mElapsedTimestampNs = event.mElapsedTimestampNs;
- mLogdTimestampNs = event.mLogdTimestampNs;
- mValues = event.mValues;
-}
-
LogEvent::LogEvent(int32_t uid, int32_t pid)
: mLogdTimestampNs(time(nullptr)), mLogUid(uid), mLogPid(pid) {
}
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 53fb5d9..a5f2460 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -216,7 +216,7 @@
/**
* Only use this if copy is absolutely needed.
*/
- LogEvent(const LogEvent&);
+ LogEvent(const LogEvent&) = default;
void parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
void parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 21ffff3..d865c21 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -122,11 +122,11 @@
}
void CountMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
- const HashableDimensionKey& primaryKey, int oldState,
- int newState) {
+ const HashableDimensionKey& primaryKey,
+ const FieldValue& oldState, const FieldValue& newState) {
VLOG("CountMetric %lld onStateChanged time %lld, State%d, key %s, %d -> %d",
(long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
- oldState, newState);
+ oldState.mValue.int_value, newState.mValue.int_value);
}
void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index f9a8842..26b3d3c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -53,8 +53,8 @@
virtual ~CountMetricProducer();
void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
- const HashableDimensionKey& primaryKey, int oldState,
- int newState) override;
+ const HashableDimensionKey& primaryKey, const FieldValue& oldState,
+ const FieldValue& newState) override;
protected:
void onMatchedLogEventInternalLocked(
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 0de92f3..6633659 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -161,13 +161,12 @@
void DurationMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
const HashableDimensionKey& primaryKey,
- const int32_t oldState, const int32_t newState) {
- // Create a FieldValue object to hold the new state.
- FieldValue value;
- value.mValue.setInt(newState);
+ const FieldValue& oldState,
+ const FieldValue& newState) {
// Check if this metric has a StateMap. If so, map the new state value to
// the correct state group id.
- mapStateValue(atomId, &value);
+ FieldValue newStateCopy = newState;
+ mapStateValue(atomId, &newStateCopy);
flushIfNeededLocked(eventTimeNs);
@@ -185,7 +184,7 @@
if (!containsLinkedStateValues(whatIt.first, primaryKey, mMetric2StateLinks, atomId)) {
continue;
}
- whatIt.second->onStateChanged(eventTimeNs, atomId, value);
+ whatIt.second->onStateChanged(eventTimeNs, atomId, newStateCopy);
}
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 6f84076..53f0f28 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -55,8 +55,8 @@
const sp<AlarmMonitor>& anomalyAlarmMonitor) override;
void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
- const HashableDimensionKey& primaryKey, const int32_t oldState,
- const int32_t newState) override;
+ const HashableDimensionKey& primaryKey, const FieldValue& oldState,
+ const FieldValue& newState) override;
protected:
void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index c4bd054..1d4d0b3 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -321,18 +321,17 @@
return;
}
vector<std::shared_ptr<LogEvent>> allData;
- if (!mPullerManager->Pull(mPullTagId, mConfigKey, &allData)) {
+ if (!mPullerManager->Pull(mPullTagId, mConfigKey, timestampNs, &allData)) {
ALOGE("Gauge Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
return;
}
const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs;
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
if (pullDelayNs > mMaxPullDelayNs) {
ALOGE("Pull finish too late for atom %d", mPullTagId);
StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
- StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
return;
}
- StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
for (const auto& data : allData) {
LogEvent localCopy = data->makeCopy();
localCopy.setElapsedTimestampNs(timestampNs);
@@ -415,6 +414,13 @@
if (!pullSuccess || allData.size() == 0) {
return;
}
+ const int64_t pullDelayNs = getElapsedRealtimeNs() - originalPullTimeNs;
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+ if (pullDelayNs > mMaxPullDelayNs) {
+ ALOGE("Pull finish too late for atom %d", mPullTagId);
+ StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
+ return;
+ }
for (const auto& data : allData) {
if (mEventMatcherWizard->matchLogEvent(
*data, mWhatMatcherIndex) == MatchingState::kMatched) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 91c98ea2..5fabb5f 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -182,8 +182,8 @@
};
void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
- const HashableDimensionKey& primaryKey, const int32_t oldState,
- const int32_t newState){};
+ const HashableDimensionKey& primaryKey, const FieldValue& oldState,
+ const FieldValue& newState){};
// Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
// This method clears all the past buckets.
@@ -442,7 +442,7 @@
bool mIsActive;
// The slice_by_state atom ids defined in statsd_config.
- std::vector<int32_t> mSlicedStateAtoms;
+ const std::vector<int32_t> mSlicedStateAtoms;
// Maps atom ids and state values to group_ids (<atom_id, <value, group_id>>).
const std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index d7ad27b..e8c575a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -71,6 +71,8 @@
mLastReportTimeNs(currentTimeNs),
mLastReportWallClockNs(getWallClockNs()),
mPullerManager(pullerManager),
+ mWhitelistedAtomIds(config.whitelisted_atom_ids().begin(),
+ config.whitelisted_atom_ids().end()),
mShouldPersistHistory(config.persist_locally()) {
// Init the ttl end timestamp.
refreshTtl(timeBaseNs);
@@ -366,11 +368,16 @@
bool MetricsManager::checkLogCredentials(const LogEvent& event) {
+ // TODO(b/154856835): Remove this check once we get whitelist from the config.
if (android::util::AtomsInfo::kWhitelistedAtoms.find(event.GetTagId()) !=
android::util::AtomsInfo::kWhitelistedAtoms.end())
{
return true;
}
+
+ if (mWhitelistedAtomIds.find(event.GetTagId()) != mWhitelistedAtomIds.end()) {
+ return true;
+ }
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
VLOG("log source %d not on the whitelist", event.GetUid());
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index ef03d20..c30532a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -189,6 +189,8 @@
// To guard access to mAllowedLogSources
mutable std::mutex mAllowedLogSourcesMutex;
+ const std::set<int32_t> mWhitelistedAtomIds;
+
// We can pull any atom from these uids.
std::set<int32_t> mDefaultPullUids;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index f34423a..f03ce45 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -182,15 +182,26 @@
}
void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
- const HashableDimensionKey& primaryKey, int oldState,
- int newState) {
+ const HashableDimensionKey& primaryKey,
+ const FieldValue& oldState, const FieldValue& newState) {
VLOG("ValueMetric %lld onStateChanged time %lld, State %d, key %s, %d -> %d",
(long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
- oldState, newState);
+ oldState.mValue.int_value, newState.mValue.int_value);
// If condition is not true, we do not need to pull for this state change.
if (mCondition != ConditionState::kTrue) {
return;
}
+
+ // If old and new states are in the same StateGroup, then we do not need to
+ // pull for this state change.
+ FieldValue oldStateCopy = oldState;
+ FieldValue newStateCopy = newState;
+ mapStateValue(atomId, &oldStateCopy);
+ mapStateValue(atomId, &newStateCopy);
+ if (oldStateCopy == newStateCopy) {
+ return;
+ }
+
bool isEventLate = eventTimeNs < mCurrentBucketStartTimeNs;
if (isEventLate) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
@@ -508,7 +519,7 @@
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
vector<std::shared_ptr<LogEvent>> allData;
- if (!mPullerManager->Pull(mPullTagId, mConfigKey, &allData)) {
+ if (!mPullerManager->Pull(mPullTagId, mConfigKey, timestampNs, &allData)) {
ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
invalidateCurrentBucket(timestampNs, BucketDropReason::PULL_FAILED);
return;
@@ -584,11 +595,6 @@
return;
}
- if (allData.size() == 0) {
- VLOG("Data pulled is empty");
- StatsdStats::getInstance().noteEmptyData(mPullTagId);
- }
-
mMatchedMetricDimensionKeys.clear();
for (const auto& data : allData) {
LogEvent localCopy = data->makeCopy();
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index c8dc8cc..751fef2 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -90,7 +90,7 @@
};
void onStateChanged(int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey,
- int oldState, int newState) override;
+ const FieldValue& oldState, const FieldValue& newState) override;
protected:
void onMatchedLogEventInternalLocked(
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 3ab44f4..210d382 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -791,10 +791,19 @@
}
noReportMetricIds.insert(no_report_metric);
}
+
+ const set<int> whitelistedAtomIds(config.whitelisted_atom_ids().begin(),
+ config.whitelisted_atom_ids().end());
for (const auto& it : allMetricProducers) {
// Register metrics to StateTrackers
for (int atomId : it->getSlicedStateAtoms()) {
- StateManager::getInstance().registerListener(atomId, it);
+ // Register listener for non-whitelisted atoms only. Using whitelisted atom as a sliced
+ // state atom is not allowed.
+ if (whitelistedAtomIds.find(atomId) == whitelistedAtomIds.end()) {
+ StateManager::getInstance().registerListener(atomId, it);
+ } else {
+ return false;
+ }
}
}
return true;
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index bed836a..361b161 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -19,6 +19,7 @@
#include "ShellSubscriber.h"
#include <android-base/file.h>
+
#include "matchers/matcher_util.h"
#include "stats_log_util.h"
@@ -32,41 +33,52 @@
void ShellSubscriber::startNewSubscription(int in, int out, int timeoutSec) {
int myToken = claimToken();
+ VLOG("ShellSubscriber: new subscription %d has come in", myToken);
mSubscriptionShouldEnd.notify_one();
shared_ptr<SubscriptionInfo> mySubscriptionInfo = make_shared<SubscriptionInfo>(in, out);
- if (!readConfig(mySubscriptionInfo)) {
- return;
- }
+ if (!readConfig(mySubscriptionInfo)) return;
- // critical-section
- std::unique_lock<std::mutex> lock(mMutex);
- if (myToken != mToken) {
- // Some other subscription has already come in. Stop.
- return;
- }
- mSubscriptionInfo = mySubscriptionInfo;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (myToken != mToken) {
+ // Some other subscription has already come in. Stop.
+ return;
+ }
+ mSubscriptionInfo = mySubscriptionInfo;
- if (mySubscriptionInfo->mPulledInfo.size() > 0 && mySubscriptionInfo->mPullIntervalMin > 0) {
- // This thread terminates after it detects that mToken has changed.
+ spawnHelperThreadsLocked(mySubscriptionInfo, myToken);
+ waitForSubscriptionToEndLocked(mySubscriptionInfo, myToken, lock, timeoutSec);
+
+ if (mSubscriptionInfo == mySubscriptionInfo) {
+ mSubscriptionInfo = nullptr;
+ }
+
+ }
+}
+
+void ShellSubscriber::spawnHelperThreadsLocked(shared_ptr<SubscriptionInfo> myInfo, int myToken) {
+ if (!myInfo->mPulledInfo.empty() && myInfo->mPullIntervalMin > 0) {
std::thread puller([this, myToken] { startPull(myToken); });
puller.detach();
}
- // Block until subscription has ended.
- if (timeoutSec > 0) {
- mSubscriptionShouldEnd.wait_for(
- lock, timeoutSec * 1s, [this, myToken, &mySubscriptionInfo] {
- return mToken != myToken || !mySubscriptionInfo->mClientAlive;
- });
- } else {
- mSubscriptionShouldEnd.wait(lock, [this, myToken, &mySubscriptionInfo] {
- return mToken != myToken || !mySubscriptionInfo->mClientAlive;
- });
- }
+ std::thread heartbeatSender([this, myToken] { sendHeartbeats(myToken); });
+ heartbeatSender.detach();
+}
- if (mSubscriptionInfo == mySubscriptionInfo) {
- mSubscriptionInfo = nullptr;
+void ShellSubscriber::waitForSubscriptionToEndLocked(shared_ptr<SubscriptionInfo> myInfo,
+ int myToken,
+ std::unique_lock<std::mutex>& lock,
+ int timeoutSec) {
+ if (timeoutSec > 0) {
+ mSubscriptionShouldEnd.wait_for(lock, timeoutSec * 1s, [this, myToken, &myInfo] {
+ return mToken != myToken || !myInfo->mClientAlive;
+ });
+ } else {
+ mSubscriptionShouldEnd.wait(lock, [this, myToken, &myInfo] {
+ return mToken != myToken || !myInfo->mClientAlive;
+ });
}
}
@@ -129,51 +141,56 @@
return true;
}
-void ShellSubscriber::startPull(int64_t myToken) {
+void ShellSubscriber::startPull(int myToken) {
+ VLOG("ShellSubscriber: pull thread %d starting", myToken);
while (true) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (!mSubscriptionInfo || mToken != myToken) {
- VLOG("Pulling thread %lld done!", (long long)myToken);
- return;
- }
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mSubscriptionInfo || mToken != myToken) {
+ VLOG("ShellSubscriber: pulling thread %d done!", myToken);
+ return;
+ }
- int64_t nowMillis = getElapsedRealtimeMillis();
- for (auto& pullInfo : mSubscriptionInfo->mPulledInfo) {
- if (pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval < nowMillis) {
- vector<std::shared_ptr<LogEvent>> data;
+ int64_t nowMillis = getElapsedRealtimeMillis();
+ int64_t nowNanos = getElapsedRealtimeNs();
+ for (PullInfo& pullInfo : mSubscriptionInfo->mPulledInfo) {
+ if (pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval >= nowMillis) {
+ continue;
+ }
+
vector<int32_t> uids;
- uids.insert(uids.end(), pullInfo.mPullUids.begin(), pullInfo.mPullUids.end());
- // This is slow. Consider storing the uids per app and listening to uidmap updates.
- for (const string& pkg : pullInfo.mPullPackages) {
- set<int32_t> uidsForPkg = mUidMap->getAppUid(pkg);
- uids.insert(uids.end(), uidsForPkg.begin(), uidsForPkg.end());
- }
- uids.push_back(DEFAULT_PULL_UID);
- mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, &data);
- VLOG("pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id());
+ getUidsForPullAtom(&uids, pullInfo);
- if (!writePulledAtomsLocked(data, pullInfo.mPullerMatcher)) {
- mSubscriptionInfo->mClientAlive = false;
- mSubscriptionShouldEnd.notify_one();
- return;
- }
+ vector<std::shared_ptr<LogEvent>> data;
+ mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, nowNanos, &data);
+ VLOG("Pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id());
+ writePulledAtomsLocked(data, pullInfo.mPullerMatcher);
+
pullInfo.mPrevPullElapsedRealtimeMs = nowMillis;
}
}
- VLOG("Pulling thread %lld sleep....", (long long)myToken);
+ VLOG("ShellSubscriber: pulling thread %d sleeping for %d ms", myToken,
+ mSubscriptionInfo->mPullIntervalMin);
std::this_thread::sleep_for(std::chrono::milliseconds(mSubscriptionInfo->mPullIntervalMin));
}
}
-// \return boolean indicating if writes were successful (will return false if
-// client dies)
-bool ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
+void ShellSubscriber::getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo) {
+ uids->insert(uids->end(), pullInfo.mPullUids.begin(), pullInfo.mPullUids.end());
+ // This is slow. Consider storing the uids per app and listening to uidmap updates.
+ for (const string& pkg : pullInfo.mPullPackages) {
+ set<int32_t> uidsForPkg = mUidMap->getAppUid(pkg);
+ uids->insert(uids->end(), uidsForPkg.begin(), uidsForPkg.end());
+ }
+ uids->push_back(DEFAULT_PULL_UID);
+}
+
+void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
const SimpleAtomMatcher& matcher) {
mProto.clear();
int count = 0;
for (const auto& event : data) {
- VLOG("%s", event->ToString().c_str());
if (matchesSimple(*mUidMap, matcher, *event)) {
count++;
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
@@ -183,55 +200,67 @@
}
}
- if (count > 0) {
- // First write the payload size.
- size_t bufferSize = mProto.size();
- if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &bufferSize,
- sizeof(bufferSize))) {
- return false;
- }
-
- VLOG("%d atoms, proto size: %zu", count, bufferSize);
- // Then write the payload.
- if (!mProto.flush(mSubscriptionInfo->mOutputFd)) {
- return false;
- }
- }
-
- return true;
+ if (count > 0) attemptWriteToSocketLocked(mProto.size());
}
void ShellSubscriber::onLogEvent(const LogEvent& event) {
std::lock_guard<std::mutex> lock(mMutex);
- if (!mSubscriptionInfo) {
- return;
- }
+ if (!mSubscriptionInfo) return;
mProto.clear();
for (const auto& matcher : mSubscriptionInfo->mPushedMatchers) {
if (matchesSimple(*mUidMap, matcher, event)) {
- VLOG("%s", event.ToString().c_str());
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event.ToProto(mProto);
mProto.end(atomToken);
+ attemptWriteToSocketLocked(mProto.size());
+ }
+ }
+}
- // First write the payload size.
- size_t bufferSize = mProto.size();
- if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &bufferSize,
- sizeof(bufferSize))) {
- mSubscriptionInfo->mClientAlive = false;
- mSubscriptionShouldEnd.notify_one();
+// Tries to write the atom encoded in mProto to the socket. If the write fails
+// because the read end of the pipe has closed, signals to other threads that
+// the subscription should end.
+void ShellSubscriber::attemptWriteToSocketLocked(size_t dataSize) {
+ // First write the payload size.
+ if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &dataSize, sizeof(dataSize))) {
+ mSubscriptionInfo->mClientAlive = false;
+ mSubscriptionShouldEnd.notify_one();
+ return;
+ }
+
+ if (dataSize == 0) return;
+
+ // Then, write the payload.
+ if (!mProto.flush(mSubscriptionInfo->mOutputFd)) {
+ mSubscriptionInfo->mClientAlive = false;
+ mSubscriptionShouldEnd.notify_one();
+ return;
+ }
+
+ mLastWriteMs = getElapsedRealtimeMillis();
+}
+
+// Send a heartbeat, consisting solely of a data size of 0, if perfd has not
+// recently received any writes from statsd. When it receives the data size of
+// 0, perfd will not expect any data and recheck whether the shell command is
+// still running.
+void ShellSubscriber::sendHeartbeats(int myToken) {
+ while (true) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mSubscriptionInfo || myToken != mToken) {
+ VLOG("ShellSubscriber: heartbeat thread %d done!", myToken);
return;
}
- // Then write the payload.
- if (!mProto.flush(mSubscriptionInfo->mOutputFd)) {
- mSubscriptionInfo->mClientAlive = false;
- mSubscriptionShouldEnd.notify_one();
- return;
+ if (getElapsedRealtimeMillis() - mLastWriteMs > kMsBetweenHeartbeats) {
+ VLOG("ShellSubscriber: sending a heartbeat to perfd");
+ attemptWriteToSocketLocked(/*dataSize=*/0);
}
}
+ std::this_thread::sleep_for(std::chrono::milliseconds(kMsBetweenHeartbeats));
}
}
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
index 61457d8..26c8a2a 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -38,11 +38,11 @@
*
* A shell subscription lasts *until shell exits*. Unlike config based clients, a shell client
* communicates with statsd via file descriptors. They can subscribe pushed and pulled atoms.
- * The atoms are sent back to the client in real time, as opposed to
- * keeping the data in memory. Shell clients do not subscribe aggregated metrics, as they are
- * responsible for doing the aggregation after receiving the atom events.
+ * The atoms are sent back to the client in real time, as opposed to keeping the data in memory.
+ * Shell clients do not subscribe aggregated metrics, as they are responsible for doing the
+ * aggregation after receiving the atom events.
*
- * Shell client pass ShellSubscription in the proto binary format. Client can update the
+ * Shell clients pass ShellSubscription in the proto binary format. Clients can update the
* subscription by sending a new subscription. The new subscription would replace the old one.
* Input data stream format is:
*
@@ -54,7 +54,7 @@
* The stream would be in the following format:
* |size_t|shellData proto|size_t|shellData proto|....
*
- * Only one shell subscriber allowed at a time, because each shell subscriber blocks one thread
+ * Only one shell subscriber is allowed at a time because each shell subscriber blocks one thread
* until it exits.
*/
class ShellSubscriber : public virtual RefBase {
@@ -100,11 +100,28 @@
bool readConfig(std::shared_ptr<SubscriptionInfo> subscriptionInfo);
- void startPull(int64_t myToken);
+ void spawnHelperThreadsLocked(std::shared_ptr<SubscriptionInfo> myInfo, int myToken);
- bool writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
+ void waitForSubscriptionToEndLocked(std::shared_ptr<SubscriptionInfo> myInfo,
+ int myToken,
+ std::unique_lock<std::mutex>& lock,
+ int timeoutSec);
+
+ void startPull(int myToken);
+
+ void writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
const SimpleAtomMatcher& matcher);
+ void getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo);
+
+ void attemptWriteToSocketLocked(size_t dataSize);
+
+ // Send ocassional heartbeats for two reasons: (a) for statsd to detect when
+ // the read end of the pipe has closed and (b) for perfd to escape a
+ // blocking read call and recheck if the user has terminated the
+ // subscription.
+ void sendHeartbeats(int myToken);
+
sp<UidMap> mUidMap;
sp<StatsPullerManager> mPullerMgr;
@@ -120,6 +137,11 @@
int mToken = 0;
const int32_t DEFAULT_PULL_UID = AID_SYSTEM;
+
+ // Tracks when we last send data to perfd. We need that time to determine
+ // when next to send a heartbeat.
+ int64_t mLastWriteMs = 0;
+ const int64_t kMsBetweenHeartbeats = 1000;
};
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
index d1af196..6388001 100644
--- a/cmds/statsd/src/state/StateListener.h
+++ b/cmds/statsd/src/state/StateListener.h
@@ -45,8 +45,8 @@
* [newState]: Current state value after state change
*/
virtual void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
- const HashableDimensionKey& primaryKey, int oldState,
- int newState) = 0;
+ const HashableDimensionKey& primaryKey, const FieldValue& oldState,
+ const FieldValue& newState) = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index b63713b..41e525c 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -35,31 +35,30 @@
HashableDimensionKey primaryKey;
filterPrimaryKey(event.getValues(), &primaryKey);
- FieldValue stateValue;
- if (!getStateFieldValueFromLogEvent(event, &stateValue)) {
+ FieldValue newState;
+ if (!getStateFieldValueFromLogEvent(event, &newState)) {
ALOGE("StateTracker error extracting state from log event. Missing exclusive state field.");
clearStateForPrimaryKey(eventTimeNs, primaryKey);
return;
}
- mField.setField(stateValue.mField.getField());
+ mField.setField(newState.mField.getField());
- if (stateValue.mValue.getType() != INT) {
+ if (newState.mValue.getType() != INT) {
ALOGE("StateTracker error extracting state from log event. Type: %d",
- stateValue.mValue.getType());
+ newState.mValue.getType());
clearStateForPrimaryKey(eventTimeNs, primaryKey);
return;
}
- const int32_t resetState = event.getResetState();
- if (resetState != -1) {
+ if (int resetState = event.getResetState(); resetState != -1) {
VLOG("StateTracker new reset state: %d", resetState);
- handleReset(eventTimeNs, resetState);
+ const FieldValue resetStateFieldValue(mField, Value(resetState));
+ handleReset(eventTimeNs, resetStateFieldValue);
return;
}
- const int32_t newState = stateValue.mValue.int_value;
- const bool nested = stateValue.mAnnotations.isNested();
+ const bool nested = newState.mAnnotations.isNested();
StateValueInfo* stateValueInfo = &mStateMap[primaryKey];
updateStateForPrimaryKey(eventTimeNs, primaryKey, newState, nested, stateValueInfo);
}
@@ -85,7 +84,7 @@
return false;
}
-void StateTracker::handleReset(const int64_t eventTimeNs, const int32_t newState) {
+void StateTracker::handleReset(const int64_t eventTimeNs, const FieldValue& newState) {
VLOG("StateTracker handle reset");
for (auto& [primaryKey, stateValueInfo] : mStateMap) {
updateStateForPrimaryKey(eventTimeNs, primaryKey, newState,
@@ -102,8 +101,9 @@
// If there is no entry for the primaryKey in mStateMap, then the state is already
// kStateUnknown.
+ const FieldValue state(mField, Value(kStateUnknown));
if (it != mStateMap.end()) {
- updateStateForPrimaryKey(eventTimeNs, primaryKey, kStateUnknown,
+ updateStateForPrimaryKey(eventTimeNs, primaryKey, state,
false /* nested; treat this state change as not nested */,
&it->second);
}
@@ -111,22 +111,26 @@
void StateTracker::updateStateForPrimaryKey(const int64_t eventTimeNs,
const HashableDimensionKey& primaryKey,
- const int32_t newState, const bool nested,
+ const FieldValue& newState, const bool nested,
StateValueInfo* stateValueInfo) {
- const int32_t oldState = stateValueInfo->state;
+ FieldValue oldState;
+ oldState.mField = mField;
+ oldState.mValue.setInt(stateValueInfo->state);
+ const int32_t oldStateValue = stateValueInfo->state;
+ const int32_t newStateValue = newState.mValue.int_value;
- if (kStateUnknown == newState) {
+ if (kStateUnknown == newStateValue) {
mStateMap.erase(primaryKey);
}
// Update state map for non-nested counting case.
// Every state event triggers a state overwrite.
if (!nested) {
- stateValueInfo->state = newState;
+ stateValueInfo->state = newStateValue;
stateValueInfo->count = 1;
// Notify listeners if state has changed.
- if (oldState != newState) {
+ if (oldStateValue != newStateValue) {
notifyListeners(eventTimeNs, primaryKey, oldState, newState);
}
return;
@@ -142,26 +146,26 @@
// In atoms.proto, a state atom with nested counting enabled
// must only have 2 states. There is no enforcemnt here of this requirement.
// The atom must be logged correctly.
- if (kStateUnknown == newState) {
- if (kStateUnknown != oldState) {
+ if (kStateUnknown == newStateValue) {
+ if (kStateUnknown != oldStateValue) {
notifyListeners(eventTimeNs, primaryKey, oldState, newState);
}
- } else if (oldState == kStateUnknown) {
- stateValueInfo->state = newState;
+ } else if (oldStateValue == kStateUnknown) {
+ stateValueInfo->state = newStateValue;
stateValueInfo->count = 1;
notifyListeners(eventTimeNs, primaryKey, oldState, newState);
- } else if (oldState == newState) {
+ } else if (oldStateValue == newStateValue) {
stateValueInfo->count++;
} else if (--stateValueInfo->count == 0) {
- stateValueInfo->state = newState;
+ stateValueInfo->state = newStateValue;
stateValueInfo->count = 1;
notifyListeners(eventTimeNs, primaryKey, oldState, newState);
}
}
void StateTracker::notifyListeners(const int64_t eventTimeNs,
- const HashableDimensionKey& primaryKey, const int32_t oldState,
- const int32_t newState) {
+ const HashableDimensionKey& primaryKey,
+ const FieldValue& oldState, const FieldValue& newState) {
for (auto l : mListeners) {
auto sl = l.promote();
if (sl != nullptr) {
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index c5f6315..abd579e 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -72,19 +72,19 @@
std::set<wp<StateListener>> mListeners;
// Reset all state values in map to the given state.
- void handleReset(const int64_t eventTimeNs, const int32_t newState);
+ void handleReset(const int64_t eventTimeNs, const FieldValue& newState);
// Clears the state value mapped to the given primary key by setting it to kStateUnknown.
void clearStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
// Update the StateMap based on the received state value.
void updateStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
- const int32_t newState, const bool nested,
+ const FieldValue& newState, const bool nested,
StateValueInfo* stateValueInfo);
// Notify registered state listeners of state change.
void notifyListeners(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
- const int32_t oldState, const int32_t newState);
+ const FieldValue& oldState, const FieldValue& newState);
};
bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 868247b..1121392 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -456,12 +456,15 @@
optional int64 pull_timeout = 10;
optional int64 pull_exceed_max_delay = 11;
optional int64 pull_failed = 12;
- optional int64 stats_companion_pull_failed = 13;
- optional int64 stats_companion_pull_binder_transaction_failed = 14;
+ optional int64 stats_companion_pull_failed = 13 [deprecated = true];
+ optional int64 stats_companion_pull_binder_transaction_failed = 14 [deprecated = true];
optional int64 empty_data = 15;
optional int64 registered_count = 16;
optional int64 unregistered_count = 17;
optional int32 atom_error_count = 18;
+ optional int64 binder_call_failed = 19;
+ optional int64 failed_uid_provider_not_found = 20;
+ optional int64 puller_not_found = 21;
}
repeated PulledAtomStats pulled_atom_stats = 10;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 2acffee..bafdfcb 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -74,12 +74,13 @@
const int FIELD_ID_PULL_TIMEOUT = 10;
const int FIELD_ID_PULL_EXCEED_MAX_DELAY = 11;
const int FIELD_ID_PULL_FAILED = 12;
-const int FIELD_ID_STATS_COMPANION_FAILED = 13;
-const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14;
const int FIELD_ID_EMPTY_DATA = 15;
const int FIELD_ID_PULL_REGISTERED_COUNT = 16;
const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17;
const int FIELD_ID_ATOM_ERROR_COUNT = 18;
+const int FIELD_ID_BINDER_CALL_FAIL_COUNT = 19;
+const int FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND = 20;
+const int FIELD_ID_PULLER_NOT_FOUND = 21;
// for AtomMetricStats proto
const int FIELD_ID_ATOM_METRIC_STATS = 17;
@@ -483,10 +484,6 @@
(long long)pair.second.pullExceedMaxDelay);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_FAILED,
(long long)pair.second.pullFailed);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_FAILED,
- (long long)pair.second.statsCompanionPullFailed);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED,
- (long long)pair.second.statsCompanionPullBinderTransactionFailed);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
(long long)pair.second.emptyData);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
@@ -494,6 +491,12 @@
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
(long long) pair.second.unregisteredCount);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_ERROR_COUNT, pair.second.atomErrorCount);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BINDER_CALL_FAIL_COUNT,
+ (long long)pair.second.binderCallFailCount);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND,
+ (long long)pair.second.pullUidProviderNotFound);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULLER_NOT_FOUND,
+ (long long)pair.second.pullerNotFound);
protoOutput->end(token);
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index c7407bd..7c0057d 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -489,6 +489,8 @@
repeated PullAtomPackages pull_atom_packages = 23;
+ repeated int32 whitelisted_atom_ids = 24;
+
// Field number 1000 is reserved for later use.
reserved 1000;
}
diff --git a/cmds/statsd/tests/AlarmMonitor_test.cpp b/cmds/statsd/tests/AlarmMonitor_test.cpp
index edbf8b5..1dc9795 100644
--- a/cmds/statsd/tests/AlarmMonitor_test.cpp
+++ b/cmds/statsd/tests/AlarmMonitor_test.cpp
@@ -49,19 +49,19 @@
EXPECT_TRUE(set.empty());
set = am.popSoonerThan(30);
- EXPECT_EQ(4u, set.size());
+ ASSERT_EQ(4u, set.size());
EXPECT_EQ(1u, set.count(a));
EXPECT_EQ(1u, set.count(b));
EXPECT_EQ(1u, set.count(c));
EXPECT_EQ(1u, set.count(d));
set = am.popSoonerThan(60);
- EXPECT_EQ(2u, set.size());
+ ASSERT_EQ(2u, set.size());
EXPECT_EQ(1u, set.count(e));
EXPECT_EQ(1u, set.count(f));
set = am.popSoonerThan(80);
- EXPECT_EQ(0u, set.size());
+ ASSERT_EQ(0u, set.size());
}
#else
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index f5ba8fd..23f8ca4 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -74,7 +74,7 @@
vector<Matcher> output;
translateFieldMatcher(matcher1, &output);
- EXPECT_EQ((size_t)1, output.size());
+ ASSERT_EQ((size_t)1, output.size());
const auto& matcher12 = output[0];
EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
@@ -95,7 +95,7 @@
vector<Matcher> output;
translateFieldMatcher(matcher1, &output);
- EXPECT_EQ((size_t)1, output.size());
+ ASSERT_EQ((size_t)1, output.size());
const auto& matcher12 = output[0];
EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
@@ -128,7 +128,7 @@
filterValues(matchers, event.getValues(), &output);
- EXPECT_EQ((size_t)7, output.getValues().size());
+ ASSERT_EQ((size_t)7, output.getValues().size());
EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
@@ -218,12 +218,12 @@
translateFieldMatcher(whatMatcher, &link.metricFields);
translateFieldMatcher(conditionMatcher, &link.conditionFields);
- EXPECT_EQ((size_t)1, link.metricFields.size());
+ ASSERT_EQ((size_t)1, link.metricFields.size());
EXPECT_EQ((int32_t)0x02010001, link.metricFields[0].mMatcher.getField());
EXPECT_EQ((int32_t)0xff7f007f, link.metricFields[0].mMask);
EXPECT_EQ((int32_t)10, link.metricFields[0].mMatcher.getTag());
- EXPECT_EQ((size_t)1, link.conditionFields.size());
+ ASSERT_EQ((size_t)1, link.conditionFields.size());
EXPECT_EQ((int32_t)0x02028002, link.conditionFields[0].mMatcher.getField());
EXPECT_EQ((int32_t)0xff7f807f, link.conditionFields[0].mMask);
EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
@@ -264,15 +264,15 @@
}
DimensionsValue result;
- EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
EXPECT_EQ(10, result.field());
EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
- EXPECT_EQ(3, result.value_tuple().dimensions_value_size());
+ ASSERT_EQ(3, result.value_tuple().dimensions_value_size());
const auto& dim1 = result.value_tuple().dimensions_value(0);
EXPECT_EQ(2, dim1.field());
- EXPECT_EQ(2, dim1.value_tuple().dimensions_value_size());
+ ASSERT_EQ(2, dim1.value_tuple().dimensions_value_size());
const auto& dim11 = dim1.value_tuple().dimensions_value(0);
EXPECT_EQ(1, dim11.field());
@@ -285,7 +285,7 @@
const auto& dim3 = result.value_tuple().dimensions_value(2);
EXPECT_EQ(6, dim3.field());
- EXPECT_EQ(1, dim3.value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, dim3.value_tuple().dimensions_value_size());
const auto& dim31 = dim3.value_tuple().dimensions_value(0);
EXPECT_EQ(2, dim31.field());
}
@@ -356,14 +356,14 @@
}
DimensionsValue result;
- EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
EXPECT_EQ(10, result.field());
EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
- EXPECT_EQ(2, result.value_tuple().dimensions_value_size());
+ ASSERT_EQ(2, result.value_tuple().dimensions_value_size());
const auto& dim1 = result.value_tuple().dimensions_value(0);
EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, dim1.value_case());
- EXPECT_EQ(3, dim1.value_tuple().dimensions_value_size());
+ ASSERT_EQ(3, dim1.value_tuple().dimensions_value_size());
const auto& dim11 = dim1.value_tuple().dimensions_value(0);
EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim11.value_case());
@@ -418,8 +418,8 @@
}
DimensionsValueTuple result;
- EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
- EXPECT_EQ(4, result.dimensions_value_size());
+ ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ ASSERT_EQ(4, result.dimensions_value_size());
const auto& dim1 = result.dimensions_value(0);
EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim1.value_case());
@@ -460,10 +460,10 @@
}
Atom result;
- EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
EXPECT_EQ(Atom::PushedCase::kBleScanResultReceived, result.pushed_case());
const auto& atom = result.ble_scan_result_received();
- EXPECT_EQ(2, atom.attribution_node_size());
+ ASSERT_EQ(2, atom.attribution_node_size());
EXPECT_EQ(1111, atom.attribution_node(0).uid());
EXPECT_EQ("location1", atom.attribution_node(0).tag());
EXPECT_EQ(2222, atom.attribution_node(1).uid());
@@ -488,7 +488,7 @@
vector<Matcher> matchers1;
translateFieldMatcher(matcher1, &matchers1);
- EXPECT_EQ(2, matchers1.size());
+ ASSERT_EQ(2, matchers1.size());
// Initialize second set of matchers
FieldMatcher matcher2;
@@ -501,7 +501,7 @@
vector<Matcher> matchers2;
translateFieldMatcher(matcher2, &matchers2);
- EXPECT_EQ(1, matchers2.size());
+ ASSERT_EQ(1, matchers2.size());
EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
EXPECT_TRUE(subsetDimensions(matchers2, matchers1));
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 00f336a..5c170c0 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -98,7 +98,7 @@
EXPECT_FALSE(logEvent.hasAttributionChain());
const vector<FieldValue>& values = logEvent.getValues();
- EXPECT_EQ(4, values.size());
+ ASSERT_EQ(4, values.size());
const FieldValue& int32Item = values[0];
Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
@@ -147,7 +147,7 @@
EXPECT_FALSE(logEvent.hasAttributionChain());
const vector<FieldValue>& values = logEvent.getValues();
- EXPECT_EQ(2, values.size());
+ ASSERT_EQ(2, values.size());
const FieldValue& stringItem = values[0];
Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
@@ -184,7 +184,7 @@
EXPECT_FALSE(logEvent.hasAttributionChain());
const vector<FieldValue>& values = logEvent.getValues();
- EXPECT_EQ(1, values.size());
+ ASSERT_EQ(1, values.size());
const FieldValue& item = values[0];
Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
@@ -213,7 +213,7 @@
EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
- EXPECT_EQ(1, values.size());
+ ASSERT_EQ(1, values.size());
const FieldValue& item = values[0];
Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
@@ -249,7 +249,7 @@
EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
- EXPECT_EQ(4, values.size()); // 2 per attribution node
+ ASSERT_EQ(4, values.size()); // 2 per attribution node
std::pair<int, int> attrIndexRange;
EXPECT_TRUE(logEvent.hasAttributionChain(&attrIndexRange));
@@ -290,7 +290,7 @@
createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_IS_UID, true);
const vector<FieldValue>& values = event.getValues();
- EXPECT_EQ(values.size(), 1);
+ ASSERT_EQ(values.size(), 1);
EXPECT_EQ(event.getUidFieldIndex(), 0);
}
@@ -299,7 +299,7 @@
createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_STATE_NESTED, true);
const vector<FieldValue>& values = event.getValues();
- EXPECT_EQ(values.size(), 1);
+ ASSERT_EQ(values.size(), 1);
EXPECT_TRUE(values[0].mAnnotations.isNested());
}
@@ -308,7 +308,7 @@
createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_PRIMARY_FIELD, true);
const vector<FieldValue>& values = event.getValues();
- EXPECT_EQ(values.size(), 1);
+ ASSERT_EQ(values.size(), 1);
EXPECT_TRUE(values[0].mAnnotations.isPrimaryField());
}
@@ -317,7 +317,7 @@
createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_EXCLUSIVE_STATE, true);
const vector<FieldValue>& values = event.getValues();
- EXPECT_EQ(values.size(), 1);
+ ASSERT_EQ(values.size(), 1);
EXPECT_TRUE(values[0].mAnnotations.isExclusiveState());
}
@@ -349,7 +349,7 @@
// Check annotation
const vector<FieldValue>& values = logEvent.getValues();
- EXPECT_EQ(values.size(), numInts + 4);
+ ASSERT_EQ(values.size(), numInts + 4);
EXPECT_TRUE(values[firstUidInChainIndex].mAnnotations.isPrimaryField());
}
@@ -359,7 +359,7 @@
createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_TRIGGER_STATE_RESET, resetState);
const vector<FieldValue>& values = event.getValues();
- EXPECT_EQ(values.size(), 1);
+ ASSERT_EQ(values.size(), 1);
EXPECT_EQ(event.getResetState(), resetState);
}
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index a44541d..b3b095b 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -29,6 +29,7 @@
#include "src/metrics/MetricProducer.h"
#include "src/metrics/ValueMetricProducer.h"
#include "src/metrics/metrics_manager_util.h"
+#include "src/state/StateManager.h"
#include "statsd_test_util.h"
using namespace testing;
@@ -309,10 +310,10 @@
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
alertTrackerMap, metricsWithActivation,
noReportMetricIds));
- EXPECT_EQ(1u, allMetricProducers.size());
- EXPECT_EQ(1u, allAnomalyTrackers.size());
- EXPECT_EQ(1u, noReportMetricIds.size());
- EXPECT_EQ(1u, alertTrackerMap.size());
+ ASSERT_EQ(1u, allMetricProducers.size());
+ ASSERT_EQ(1u, allAnomalyTrackers.size());
+ ASSERT_EQ(1u, noReportMetricIds.size());
+ ASSERT_EQ(1u, alertTrackerMap.size());
EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
}
@@ -591,6 +592,58 @@
EXPECT_TRUE(isSubset(defaultPullUids, set<int32_t>(atom3Uids.begin(), atom3Uids.end())));
}
+TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
+ sp<UidMap> uidMap;
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+
+ StatsdConfig config = buildGoodConfig();
+ config.add_whitelisted_atom_ids(3);
+ config.add_whitelisted_atom_ids(4);
+
+ MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
+ pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
+
+ LogEvent event(0 /* uid */, 0 /* pid */);
+ CreateNoValuesLogEvent(&event, 10 /* atom id */, 0 /* timestamp */);
+ EXPECT_FALSE(metricsManager.checkLogCredentials(event));
+
+ CreateNoValuesLogEvent(&event, 3 /* atom id */, 0 /* timestamp */);
+ EXPECT_TRUE(metricsManager.checkLogCredentials(event));
+
+ CreateNoValuesLogEvent(&event, 4 /* atom id */, 0 /* timestamp */);
+ EXPECT_TRUE(metricsManager.checkLogCredentials(event));
+}
+
+TEST(MetricsManagerTest, TestWhitelistedAtomStateTracker) {
+ sp<UidMap> uidMap;
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+
+ StatsdConfig config = buildGoodConfig();
+ config.add_allowed_log_source("AID_SYSTEM");
+ config.add_whitelisted_atom_ids(3);
+ config.add_whitelisted_atom_ids(4);
+
+ State state;
+ state.set_id(1);
+ state.set_atom_id(3);
+
+ *config.add_state() = state;
+
+ config.mutable_count_metric(0)->add_slice_by_state(state.id());
+
+ StateManager::getInstance().clear();
+
+ MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
+ pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
+
+ EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_FALSE(metricsManager.isConfigValid());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index e6144c5..076f327 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -187,7 +187,7 @@
EXPECT_TRUE(output.reports_size() > 0);
auto uidmap = output.reports(0).uid_map();
EXPECT_TRUE(uidmap.snapshots_size() > 0);
- EXPECT_EQ(2, uidmap.snapshots(0).package_info_size());
+ ASSERT_EQ(2, uidmap.snapshots(0).package_info_size());
}
TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) {
@@ -248,7 +248,7 @@
output.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(output.reports_size() > 0);
auto report = output.reports(0);
- EXPECT_EQ(1, report.annotation_size());
+ ASSERT_EQ(1, report.annotation_size());
EXPECT_EQ(1, report.annotation(0).field_int64());
EXPECT_EQ(2, report.annotation(0).field_int32());
}
@@ -281,16 +281,16 @@
processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST,
&bytes);
output.ParseFromArray(bytes.data(), bytes.size());
- EXPECT_EQ(output.reports_size(), 1);
- EXPECT_EQ(output.reports(0).metrics_size(), 1);
- EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
+ ASSERT_EQ(output.reports_size(), 1);
+ ASSERT_EQ(output.reports(0).metrics_size(), 1);
+ ASSERT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
// Dump report WITH erasing data. There should be data since we didn't previously erase it.
processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
output.ParseFromArray(bytes.data(), bytes.size());
- EXPECT_EQ(output.reports_size(), 1);
- EXPECT_EQ(output.reports(0).metrics_size(), 1);
- EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
+ ASSERT_EQ(output.reports_size(), 1);
+ ASSERT_EQ(output.reports(0).metrics_size(), 1);
+ ASSERT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
// Dump report again. There should be no data since we erased it.
processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
@@ -438,7 +438,7 @@
processor.OnConfigUpdated(2, cfgKey2, config2);
processor.OnConfigUpdated(3, cfgKey3, config3);
- EXPECT_EQ(3, processor.mMetricsManagers.size());
+ ASSERT_EQ(3, processor.mMetricsManagers.size());
// Expect the first config and both metrics in it to be active.
auto it = processor.mMetricsManagers.find(cfgKey1);
@@ -535,7 +535,7 @@
// A broadcast should have happened, and all 3 configs should be active in the broadcast.
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 3);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 3);
EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId1) !=
activeConfigsBroadcast.end());
EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId2) !=
@@ -560,7 +560,7 @@
processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
- EXPECT_EQ(3, processor2->mMetricsManagers.size());
+ ASSERT_EQ(3, processor2->mMetricsManagers.size());
// First config and both metrics are active.
it = processor2->mMetricsManagers.find(cfgKey1);
@@ -619,7 +619,7 @@
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1003 = it->second;
EXPECT_FALSE(metricsManager1003->isActive());
- EXPECT_EQ(2, metricsManager1003->mAllMetricProducers.size());
+ ASSERT_EQ(2, metricsManager1003->mAllMetricProducers.size());
metricIt = metricsManager1003->mAllMetricProducers.begin();
for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
@@ -702,7 +702,7 @@
sp<StatsLogProcessor> processor =
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
- EXPECT_EQ(1, processor->mMetricsManagers.size());
+ ASSERT_EQ(1, processor->mMetricsManagers.size());
auto it = processor->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor->mMetricsManagers.end());
auto& metricsManager1 = it->second;
@@ -752,7 +752,7 @@
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
- EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ ASSERT_EQ(1, processor2->mMetricsManagers.size());
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1001 = it->second;
@@ -835,7 +835,7 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor->mMetricsManagers.size());
+ ASSERT_EQ(1, processor->mMetricsManagers.size());
auto it = processor->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor->mMetricsManagers.end());
auto& metricsManager1 = it->second;
@@ -920,7 +920,7 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ ASSERT_EQ(1, processor2->mMetricsManagers.size());
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1001 = it->second;
@@ -1021,7 +1021,7 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor3->mMetricsManagers.size());
+ ASSERT_EQ(1, processor3->mMetricsManagers.size());
it = processor3->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
auto& metricsManagerTimeBase3 = it->second;
@@ -1123,7 +1123,7 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor4->mMetricsManagers.size());
+ ASSERT_EQ(1, processor4->mMetricsManagers.size());
it = processor4->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor4->mMetricsManagers.end());
auto& metricsManagerTimeBase4 = it->second;
@@ -1237,13 +1237,13 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor1->mMetricsManagers.size());
+ ASSERT_EQ(1, processor1->mMetricsManagers.size());
auto it = processor1->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor1->mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
- EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
+ ASSERT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
// We assume that the index of a MetricProducer within the mAllMetricProducers
// array follows the order in which metrics are added to the config.
auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
@@ -1254,7 +1254,7 @@
EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
EXPECT_TRUE(metricProducer1_2->isActive());
- EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
+ ASSERT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
// that matchers are indexed in the order that they are added to the config.
const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
@@ -1303,13 +1303,13 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ ASSERT_EQ(1, processor2->mMetricsManagers.size());
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager2 = it->second;
EXPECT_TRUE(metricsManager2->isActive());
- EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
+ ASSERT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
// We assume that the index of a MetricProducer within the mAllMetricProducers
// array follows the order in which metrics are added to the config.
auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
@@ -1320,7 +1320,7 @@
EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
EXPECT_TRUE(metricProducer2_2->isActive());
- EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
+ ASSERT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
// that matchers are indexed in the order that they are added to the config.
const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
@@ -1387,13 +1387,13 @@
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor3->mMetricsManagers.size());
+ ASSERT_EQ(1, processor3->mMetricsManagers.size());
it = processor3->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
auto& metricsManager3 = it->second;
EXPECT_TRUE(metricsManager3->isActive());
- EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
+ ASSERT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
// We assume that the index of a MetricProducer within the mAllMetricProducers
// array follows the order in which metrics are added to the config.
auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
@@ -1404,7 +1404,7 @@
EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
EXPECT_TRUE(metricProducer3_2->isActive());
- EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
+ ASSERT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
// that matchers are indexed in the order that they are added to the config.
const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
@@ -1531,12 +1531,12 @@
// Metric 3 is active.
// {{{---------------------------------------------------------------------------
sp<StatsLogProcessor> processor = service->mProcessor;
- EXPECT_EQ(1, processor->mMetricsManagers.size());
+ ASSERT_EQ(1, processor->mMetricsManagers.size());
auto it = processor->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor->mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
- EXPECT_EQ(3, metricsManager1->mAllMetricProducers.size());
+ ASSERT_EQ(3, metricsManager1->mAllMetricProducers.size());
auto& metricProducer1 = metricsManager1->mAllMetricProducers[0];
EXPECT_EQ(metricId1, metricProducer1->getMetricId());
@@ -1551,7 +1551,7 @@
EXPECT_TRUE(metricProducer3->isActive());
// Check event activations.
- EXPECT_EQ(metricsManager1->mAllAtomMatchers.size(), 4);
+ ASSERT_EQ(metricsManager1->mAllAtomMatchers.size(), 4);
EXPECT_EQ(metricsManager1->mAllAtomMatchers[0]->getId(),
metric1ActivationTrigger1->atom_matcher_id());
const auto& activation1 = metricProducer1->mEventActivationMap.at(0);
@@ -1628,12 +1628,12 @@
// We should have a new metrics manager. Lets get it and ensure activation status is restored.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor->mMetricsManagers.size());
+ ASSERT_EQ(1, processor->mMetricsManagers.size());
it = processor->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor->mMetricsManagers.end());
auto& metricsManager2 = it->second;
EXPECT_TRUE(metricsManager2->isActive());
- EXPECT_EQ(3, metricsManager2->mAllMetricProducers.size());
+ ASSERT_EQ(3, metricsManager2->mAllMetricProducers.size());
auto& metricProducer1001 = metricsManager2->mAllMetricProducers[0];
EXPECT_EQ(metricId1, metricProducer1001->getMetricId());
@@ -1651,7 +1651,7 @@
// Activation 1 is kActiveOnBoot.
// Activation 2 and 3 are not active.
// Activation 4 is active.
- EXPECT_EQ(metricsManager2->mAllAtomMatchers.size(), 4);
+ ASSERT_EQ(metricsManager2->mAllAtomMatchers.size(), 4);
EXPECT_EQ(metricsManager2->mAllAtomMatchers[0]->getId(),
metric1ActivationTrigger1->atom_matcher_id());
const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0);
@@ -1709,7 +1709,7 @@
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
- EXPECT_EQ(3, actualFieldValues->size());
+ ASSERT_EQ(3, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ(field1, actualFieldValues->at(1).mValue.int_value);
EXPECT_EQ(field2, actualFieldValues->at(2).mValue.int_value);
@@ -1734,7 +1734,7 @@
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
- EXPECT_EQ(3, actualFieldValues->size());
+ ASSERT_EQ(3, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ(field1, actualFieldValues->at(1).mValue.int_value);
EXPECT_EQ(field2, actualFieldValues->at(2).mValue.int_value);
@@ -1759,7 +1759,7 @@
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
- EXPECT_EQ(6, actualFieldValues->size());
+ ASSERT_EQ(6, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
EXPECT_EQ(200, actualFieldValues->at(2).mValue.int_value);
@@ -1787,7 +1787,7 @@
processor->OnLogEvent(logEvent.get());
const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
- EXPECT_EQ(6, actualFieldValues->size());
+ ASSERT_EQ(6, actualFieldValues->size());
EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
EXPECT_EQ(200, actualFieldValues->at(2).mValue.int_value);
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 29005a2..293e8ed 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -86,7 +86,7 @@
EXPECT_FALSE(m.hasApp(1000, "not.app"));
std::set<string> name_set = m.getAppNamesFromUid(1000u, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 2u);
+ ASSERT_EQ(name_set.size(), 2u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
@@ -115,7 +115,7 @@
m.updateMap(1, uids, versions, versionStrings, apps, installers);
std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 2u);
+ ASSERT_EQ(name_set.size(), 2u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
@@ -124,7 +124,7 @@
EXPECT_EQ(40, m.getAppVersion(1000, kApp1));
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 2u);
+ ASSERT_EQ(name_set.size(), 2u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
@@ -132,7 +132,7 @@
EXPECT_FALSE(m.hasApp(1000, kApp1));
EXPECT_TRUE(m.hasApp(1000, kApp2));
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 1u);
+ ASSERT_EQ(name_set.size(), 1u);
EXPECT_TRUE(name_set.find(kApp1) == name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
@@ -149,14 +149,14 @@
m.updateMap(1, {1000, 1000}, {4, 5}, {String16("v4"), String16("v5")},
{String16(kApp1.c_str()), String16(kApp2.c_str())}, {String16(""), String16("")});
std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 2u);
+ ASSERT_EQ(name_set.size(), 2u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
// Adds a new name for uid 1000.
m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40, String16("v40"), String16(""));
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 3u);
+ ASSERT_EQ(name_set.size(), 3u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
@@ -165,7 +165,7 @@
// This name is also reused by another uid 2000.
m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1, String16("v1"), String16(""));
name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */);
- EXPECT_EQ(name_set.size(), 1u);
+ ASSERT_EQ(name_set.size(), 1u);
EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
}
@@ -212,7 +212,7 @@
// Check there's still a uidmap attached this one.
UidMapping results;
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots_size());
+ ASSERT_EQ(1, results.snapshots_size());
EXPECT_EQ("v1", results.snapshots(0).package_info(0).version_string());
}
@@ -240,7 +240,7 @@
// Snapshot should still contain this item as deleted.
UidMapping results;
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots(0).package_info_size());
+ ASSERT_EQ(1, results.snapshots(0).package_info_size());
EXPECT_EQ(true, results.snapshots(0).package_info(0).deleted());
}
@@ -269,7 +269,7 @@
ProtoOutputStream proto;
m.appendUidMap(3, config1, nullptr, true, true, &proto);
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
+ ASSERT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
// Now remove all the apps.
m.updateMap(1, uids, versions, versionStrings, apps, installers);
@@ -281,7 +281,7 @@
m.appendUidMap(5, config1, nullptr, true, true, &proto);
// Snapshot drops the first nine items.
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
+ ASSERT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
}
TEST(UidMapTest, TestClearingOutput) {
@@ -313,44 +313,44 @@
m.appendUidMap(2, config1, nullptr, true, true, &proto);
UidMapping results;
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots_size());
+ ASSERT_EQ(1, results.snapshots_size());
// We have to keep at least one snapshot in memory at all times.
proto.clear();
m.appendUidMap(2, config1, nullptr, true, true, &proto);
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots_size());
+ ASSERT_EQ(1, results.snapshots_size());
// Now add another configuration.
m.OnConfigUpdated(config2);
m.updateApp(5, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""));
- EXPECT_EQ(1U, m.mChanges.size());
+ ASSERT_EQ(1U, m.mChanges.size());
proto.clear();
m.appendUidMap(6, config1, nullptr, true, true, &proto);
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots_size());
- EXPECT_EQ(1, results.changes_size());
- EXPECT_EQ(1U, m.mChanges.size());
+ ASSERT_EQ(1, results.snapshots_size());
+ ASSERT_EQ(1, results.changes_size());
+ ASSERT_EQ(1U, m.mChanges.size());
// Add another delta update.
m.updateApp(7, String16(kApp2.c_str()), 1001, 41, String16("v41"), String16(""));
- EXPECT_EQ(2U, m.mChanges.size());
+ ASSERT_EQ(2U, m.mChanges.size());
// We still can't remove anything.
proto.clear();
m.appendUidMap(8, config1, nullptr, true, true, &proto);
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots_size());
- EXPECT_EQ(1, results.changes_size());
- EXPECT_EQ(2U, m.mChanges.size());
+ ASSERT_EQ(1, results.snapshots_size());
+ ASSERT_EQ(1, results.changes_size());
+ ASSERT_EQ(2U, m.mChanges.size());
proto.clear();
m.appendUidMap(9, config2, nullptr, true, true, &proto);
protoOutputStreamToUidMapping(&proto, &results);
- EXPECT_EQ(1, results.snapshots_size());
- EXPECT_EQ(2, results.changes_size());
+ ASSERT_EQ(1, results.snapshots_size());
+ ASSERT_EQ(2, results.changes_size());
// At this point both should be cleared.
- EXPECT_EQ(0U, m.mChanges.size());
+ ASSERT_EQ(0U, m.mChanges.size());
}
TEST(UidMapTest, TestMemoryComputed) {
@@ -408,13 +408,13 @@
m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2,
String16("v2"), String16(""));
- EXPECT_EQ(1U, m.mChanges.size());
+ ASSERT_EQ(1U, m.mChanges.size());
// Now force deletion by limiting the memory to hold one delta change.
m.maxBytesOverride = 120; // Since the app string alone requires >45 characters.
m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4,
String16("v4"), String16(""));
- EXPECT_EQ(1U, m.mChanges.size());
+ ASSERT_EQ(1U, m.mChanges.size());
}
#else
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
index 90ffcd0..322cfaf 100644
--- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
@@ -56,7 +56,7 @@
currentTimeSec = startMillis / MS_PER_SEC + 7000;
firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
- EXPECT_EQ(firedAlarmSet.size(), 1u);
+ ASSERT_EQ(firedAlarmSet.size(), 1u);
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
EXPECT_TRUE(firedAlarmSet.empty());
EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60));
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 6bde79f..0cc8af1 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -149,7 +149,7 @@
std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}});
// Start time with no events.
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
// Event from bucket #0 occurs.
@@ -160,7 +160,7 @@
// Adds past bucket #0
anomalyTracker.addPastBucket(bucket0, 0);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
@@ -174,7 +174,7 @@
// Adds past bucket #0 again. The sum does not change.
anomalyTracker.addPastBucket(bucket0, 0);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
@@ -187,7 +187,7 @@
// Adds past bucket #1.
anomalyTracker.addPastBucket(bucket1, 1);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
@@ -201,7 +201,7 @@
// Adds past bucket #1 again. Nothing changes.
anomalyTracker.addPastBucket(bucket1, 1);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
@@ -214,7 +214,7 @@
// Adds past bucket #2.
anomalyTracker.addPastBucket(bucket2, 2);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
@@ -227,7 +227,7 @@
// Adds bucket #3.
anomalyTracker.addPastBucket(bucket3, 3L);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
@@ -240,7 +240,7 @@
// Adds bucket #4.
anomalyTracker.addPastBucket(bucket4, 4);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
@@ -253,7 +253,7 @@
// Adds bucket #5.
anomalyTracker.addPastBucket(bucket5, 5);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
@@ -294,7 +294,7 @@
int64_t eventTimestamp6 = bucketSizeNs * 27 + 3;
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 9, bucket9, {}, {keyA, keyB, keyC, keyD}));
detectAndDeclareAnomalies(anomalyTracker, 9, bucket9, eventTimestamp1);
checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
@@ -303,15 +303,15 @@
// Add past bucket #9
anomalyTracker.addPastBucket(bucket9, 9);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD}));
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
{{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
@@ -319,27 +319,27 @@
// Add past bucket #16
anomalyTracker.addPastBucket(bucket16, 16);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 18, bucket18, {keyB}, {keyA, keyC, keyD}));
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
// Within refractory period.
detectAndDeclareAnomalies(anomalyTracker, 18, bucket18, eventTimestamp3);
checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
{{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
// Add past bucket #18
anomalyTracker.addPastBucket(bucket18, 18);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4);
@@ -349,11 +349,11 @@
// Add bucket #18 again. Nothing changes.
anomalyTracker.addPastBucket(bucket18, 18);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4 + 1);
@@ -364,12 +364,12 @@
// Add past bucket #20
anomalyTracker.addPastBucket(bucket20, 20);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5);
checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
{{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
@@ -377,14 +377,14 @@
// Add past bucket #25
anomalyTracker.addPastBucket(bucket25, 25);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {},
{keyA, keyB, keyC, keyD, keyE}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
{{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
@@ -393,9 +393,9 @@
EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE},
{keyA, keyB, keyC, keyD}));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7);
- EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+ ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
{{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}});
}
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index ba5b032..86e24fb 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -306,13 +306,13 @@
changedCache);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
- EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u);
+ ASSERT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u);
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
} else {
EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(),
@@ -338,9 +338,9 @@
changedCache);
EXPECT_FALSE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
- EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
@@ -359,9 +359,9 @@
// nothing changes, because wake lock 2 is still held for this uid
EXPECT_FALSE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
- EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
@@ -375,10 +375,10 @@
changedCache[0] = false;
conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
changedCache);
- EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u);
+ ASSERT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u);
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
} else {
EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(),
@@ -432,7 +432,7 @@
conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
changedCache);
- EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
// Now test query
@@ -480,7 +480,7 @@
changedCache[0] = false;
conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
changedCache);
- EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
// query again
@@ -524,14 +524,14 @@
conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
changedCache);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
- EXPECT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
{
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ ASSERT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
} else {
EXPECT_EQ(uids1.size(),
@@ -560,14 +560,14 @@
conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
} else {
- EXPECT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
{
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ ASSERT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
} else {
EXPECT_EQ(uids2.size(),
@@ -597,10 +597,10 @@
conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_TRUE(changedCache[0]);
- EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
{
if (position == Position::FIRST || position == Position::LAST) {
- EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ ASSERT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
} else {
EXPECT_EQ(uids1.size() + uids2.size(),
diff --git a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
index 9ea0b81..93b2783 100644
--- a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
@@ -52,9 +52,9 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(2u, processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers.size());
+ ASSERT_EQ(2u, processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers.size());
auto alarmTracker1 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[0];
auto alarmTracker2 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[1];
@@ -68,7 +68,7 @@
const int64_t alarmFiredTimestampSec0 = alarmTimestampSec1 + 5;
auto alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(alarmFiredTimestampSec0));
- EXPECT_EQ(1u, alarmSet.size());
+ ASSERT_EQ(1u, alarmSet.size());
processor->onPeriodicAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec());
EXPECT_EQ(alarmTimestampSec1 + 30 * 60, alarmTracker2->getAlarmTimestampSec());
@@ -77,7 +77,7 @@
const int64_t alarmFiredTimestampSec1 = alarmTimestampSec0 + 2 * 60 * 60 + 125;
alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(alarmFiredTimestampSec1));
- EXPECT_EQ(2u, alarmSet.size());
+ ASSERT_EQ(2u, alarmSet.size());
processor->onPeriodicAlarmFired(alarmFiredTimestampSec1 * NS_PER_SEC, alarmSet);
EXPECT_EQ(alarmTimestampSec0 + 60 * 60 * 3, alarmTracker1->getAlarmTimestampSec());
EXPECT_EQ(alarmTimestampSec1 + 30 * 60 * 5, alarmTracker2->getAlarmTimestampSec());
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index c2d7043..af9436b 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -66,9 +66,9 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -183,9 +183,9 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -254,16 +254,16 @@
int64_t configId = 1000;
ConfigKey cfgKey(configUid, configId);
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
metadata::StatsMetadataList result;
int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
- EXPECT_EQ(result.stats_metadata_size(), 0);
+ ASSERT_EQ(result.stats_metadata_size(), 0);
}
TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk) {
@@ -279,9 +279,9 @@
int64_t configId = 1000;
ConfigKey cfgKey(configUid, configId);
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -308,15 +308,15 @@
processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
metadata::StatsMetadata statsMetadata = result.stats_metadata(0);
- EXPECT_EQ(result.stats_metadata_size(), 1);
+ ASSERT_EQ(result.stats_metadata_size(), 1);
EXPECT_EQ(statsMetadata.config_key().config_id(), configId);
EXPECT_EQ(statsMetadata.config_key().uid(), configUid);
metadata::AlertMetadata alertMetadata = statsMetadata.alert_metadata(0);
- EXPECT_EQ(statsMetadata.alert_metadata_size(), 1);
+ ASSERT_EQ(statsMetadata.alert_metadata_size(), 1);
EXPECT_EQ(alertMetadata.alert_id(), alert_id);
metadata::AlertDimensionKeyedData keyedData = alertMetadata.alert_dim_keyed_data(0);
- EXPECT_EQ(alertMetadata.alert_dim_keyed_data_size(), 1);
+ ASSERT_EQ(alertMetadata.alert_dim_keyed_data_size(), 1);
EXPECT_EQ(keyedData.last_refractory_ends_sec(),
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
mockElapsedTimeNs / NS_PER_SEC +
@@ -342,9 +342,9 @@
int64_t configId = 1000;
ConfigKey cfgKey(configUid, configId);
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
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 4f9f315..95e3010 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -104,9 +104,9 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -162,7 +162,7 @@
// Anomaly alarm fired.
auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(alarmFiredTimestampSec0));
- EXPECT_EQ(1u, alarmSet.size());
+ ASSERT_EQ(1u, alarmSet.size());
processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
@@ -199,7 +199,7 @@
alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(alarmFiredTimestampSec1));
- EXPECT_EQ(0u, alarmSet.size());
+ ASSERT_EQ(0u, alarmSet.size());
// Acquire wakelock wl1 near the end of bucket #0.
acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
@@ -285,9 +285,9 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -406,9 +406,9 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -439,7 +439,7 @@
const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
- EXPECT_EQ(1u, alarmSet.size());
+ ASSERT_EQ(1u, alarmSet.size());
processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 52229e2..4c2caa9 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -101,7 +101,7 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
// Here it assumes that GMS core has two uids.
@@ -155,17 +155,17 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(countMetrics.data_size(), 4);
+ ASSERT_EQ(countMetrics.data_size(), 4);
auto data = countMetrics.data(0);
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
+ ASSERT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 2);
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
@@ -178,7 +178,7 @@
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 222,
"GMSCoreModule1");
- EXPECT_EQ(data.bucket_info_size(), 2);
+ ASSERT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
@@ -190,7 +190,7 @@
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 222,
"GMSCoreModule3");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
bucketStartTimeNs + 3 * bucketSizeNs);
@@ -200,7 +200,7 @@
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 444,
"GMSCoreModule2");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
bucketStartTimeNs + 2 * bucketSizeNs);
@@ -214,7 +214,7 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
// Here it assumes that GMS core has two uids.
@@ -268,18 +268,18 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(countMetrics.data_size(), 6);
+ ASSERT_EQ(countMetrics.data_size(), 6);
auto data = countMetrics.data(0);
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 222,
"GMSCoreModule1");
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -296,7 +296,7 @@
ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 333);
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
util::WAKELOCK_STATE_CHANGED, 333, "App3");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
@@ -310,7 +310,7 @@
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
util::WAKELOCK_STATE_CHANGED, 222,
"GMSCoreModule1");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -327,7 +327,7 @@
ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 333);
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
util::WAKELOCK_STATE_CHANGED, 333, "App3");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -343,7 +343,7 @@
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
util::WAKELOCK_STATE_CHANGED, 222,
"GMSCoreModule1");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -359,7 +359,7 @@
ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 333);
ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
util::WAKELOCK_STATE_CHANGED, 333, "App3");
- EXPECT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index 16adbdd..0bce0ba 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -68,7 +68,7 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
std::vector<int> attributionUids1 = {111};
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index b1461a1..1a7cd558 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -65,14 +65,14 @@
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
// Check that CountMetricProducer was initialized correctly.
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
// Check that StateTrackers were initialized correctly.
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
@@ -132,23 +132,23 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(3, countMetrics.data_size());
+ ASSERT_EQ(3, countMetrics.data_size());
// For each CountMetricData, check StateValue info is correct and buckets
// have correct counts.
auto data = countMetrics.data(0);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
@@ -157,7 +157,7 @@
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(1);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
@@ -166,7 +166,7 @@
EXPECT_EQ(2, data.bucket_info(1).count());
data = countMetrics.data(2);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
@@ -220,14 +220,14 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
// Check that CountMetricProducer was initialized correctly.
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
StateMap map = state.map();
for (auto group : map.group()) {
@@ -316,44 +316,44 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(3, countMetrics.data_size());
+ ASSERT_EQ(3, countMetrics.data_size());
// For each CountMetricData, check StateValue info is correct and buckets
// have correct counts.
auto data = countMetrics.data(0);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(1);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(1, data.bucket_info(1).count());
data = countMetrics.data(2);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(4, data.bucket_info(0).count());
EXPECT_EQ(2, data.bucket_info(1).count());
}
@@ -405,15 +405,15 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
// Check that CountMetricProducer was initialized correctly.
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
- EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ ASSERT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
/*
NOTE: "1" or "2" represents the uid associated with the state/app crash event
@@ -496,23 +496,23 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(5, countMetrics.data_size());
+ ASSERT_EQ(5, countMetrics.data_size());
// For each CountMetricData, check StateValue info is correct and buckets
// have correct counts.
auto data = countMetrics.data(0);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
@@ -520,7 +520,7 @@
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(1);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
@@ -528,7 +528,7 @@
EXPECT_EQ(2, data.bucket_info(0).count());
data = countMetrics.data(2);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
@@ -537,7 +537,7 @@
EXPECT_EQ(2, data.bucket_info(1).count());
data = countMetrics.data(3);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
@@ -545,7 +545,7 @@
EXPECT_EQ(2, data.bucket_info(0).count());
data = countMetrics.data(4);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
@@ -600,16 +600,16 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
// Check that CountMetricProducer was initialized correctly.
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
- EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
+ ASSERT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
StateMap map = state1.map();
for (auto group : map.group()) {
@@ -726,23 +726,23 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(6, countMetrics.data_size());
+ ASSERT_EQ(6, countMetrics.data_size());
// For each CountMetricData, check StateValue info is correct and buckets
// have correct counts.
auto data = countMetrics.data(0);
- EXPECT_EQ(2, data.slice_by_state_size());
+ ASSERT_EQ(2, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1, data.slice_by_state(0).value());
@@ -753,7 +753,7 @@
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(1);
- EXPECT_EQ(2, data.slice_by_state_size());
+ ASSERT_EQ(2, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
@@ -764,7 +764,7 @@
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(2);
- EXPECT_EQ(2, data.slice_by_state_size());
+ ASSERT_EQ(2, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
@@ -775,7 +775,7 @@
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(3);
- EXPECT_EQ(2, data.slice_by_state_size());
+ ASSERT_EQ(2, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
@@ -786,7 +786,7 @@
EXPECT_EQ(2, data.bucket_info(0).count());
data = countMetrics.data(4);
- EXPECT_EQ(2, data.slice_by_state_size());
+ ASSERT_EQ(2, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
@@ -797,7 +797,7 @@
EXPECT_EQ(1, data.bucket_info(0).count());
data = countMetrics.data(5);
- EXPECT_EQ(2, data.slice_by_state_size());
+ ASSERT_EQ(2, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index d59ec3e..4efb038 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -57,10 +57,10 @@
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
@@ -93,18 +93,18 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(1, durationMetrics.data_size());
+ ASSERT_EQ(1, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -140,10 +140,10 @@
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
@@ -176,18 +176,18 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(1, durationMetrics.data_size());
+ ASSERT_EQ(1, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
EXPECT_EQ(0, bucketInfo.bucket_num());
@@ -253,16 +253,16 @@
processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
- EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
- EXPECT_EQ(eventActivationMap.size(), 1u);
+ ASSERT_EQ(eventActivationMap.size(), 1u);
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
@@ -289,7 +289,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
@@ -302,8 +302,8 @@
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 2);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
- EXPECT_EQ(eventActivationMap.size(), 1u);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(eventActivationMap.size(), 1u);
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
@@ -333,7 +333,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
@@ -347,18 +347,18 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(1, durationMetrics.data_size());
+ ASSERT_EQ(1, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
EXPECT_EQ(0, bucketInfo.bucket_num());
@@ -393,10 +393,10 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
EXPECT_TRUE(metricsManager->isActive());
@@ -428,23 +428,23 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(1, durationMetrics.data_size());
+ ASSERT_EQ(1, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
// Validate bucket info.
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
@@ -497,10 +497,10 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
EXPECT_TRUE(metricsManager->isActive());
@@ -530,25 +530,25 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(1, durationMetrics.data_size());
+ ASSERT_EQ(1, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
// Validate dimension value.
ValidateAttributionUidDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, appUid);
// Validate bucket info.
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
@@ -608,15 +608,15 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
- EXPECT_EQ(eventActivationMap.size(), 1u);
+ ASSERT_EQ(eventActivationMap.size(), 1u);
EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
@@ -691,25 +691,25 @@
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
FAST, &buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(1, durationMetrics.data_size());
+ ASSERT_EQ(1, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
// Validate dimension value.
ValidateAttributionUidDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, appUid);
// Validate bucket info.
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
@@ -753,16 +753,16 @@
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
EXPECT_TRUE(metricsManager->isActive());
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_TRUE(metricProducer->mIsActive);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
// Check that StateTrackers were initialized correctly.
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
@@ -814,26 +814,26 @@
processor->onDumpReport(cfgKey, bucketStartTimeNs + 360 * NS_PER_SEC,
true /* include current partial bucket */, true, ADB_DUMP, FAST,
&buffer); // 6:10
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(3, durationMetrics.data_size());
+ ASSERT_EQ(3, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -842,11 +842,11 @@
EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
data = durationMetrics.data(1);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(110 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -855,11 +855,11 @@
EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
data = durationMetrics.data(2);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, data.slice_by_state(0).value());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -902,16 +902,16 @@
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
EXPECT_TRUE(metricsManager->isActive());
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_TRUE(metricProducer->mIsActive);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
// Check that StateTrackers were initialized correctly.
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
@@ -976,26 +976,26 @@
processor->onDumpReport(cfgKey, bucketStartTimeNs + 410 * NS_PER_SEC,
true /* include current partial bucket */, true, ADB_DUMP, FAST,
&buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(3, durationMetrics.data_size());
+ ASSERT_EQ(3, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(45 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -1004,11 +1004,11 @@
EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
data = durationMetrics.data(1);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(45 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -1017,11 +1017,11 @@
EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
data = durationMetrics.data(2);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, data.slice_by_state(0).value());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -1060,16 +1060,16 @@
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
EXPECT_TRUE(metricsManager->isActive());
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_TRUE(metricProducer->mIsActive);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
// Check that StateTrackers were initialized correctly.
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
@@ -1134,26 +1134,26 @@
processor->onDumpReport(cfgKey, bucketStartTimeNs + 490 * NS_PER_SEC,
true /* include current partial bucket */, true, ADB_DUMP, FAST,
&buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(2, durationMetrics.data_size());
+ ASSERT_EQ(2, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(130 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -1162,11 +1162,11 @@
EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
data = durationMetrics.data(1);
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -1216,7 +1216,7 @@
// This config is rejected because the dimension in what fields are not a superset of the sliced
// state primary fields.
- EXPECT_EQ(processor->mMetricsManagers.size(), 0);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 0);
}
TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) {
@@ -1261,16 +1261,16 @@
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
EXPECT_TRUE(metricsManager->isActive());
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_TRUE(metricProducer->mIsActive);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
- EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
// Check that StateTrackers were initialized correctly.
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
@@ -1328,24 +1328,24 @@
processor->onDumpReport(cfgKey, bucketStartTimeNs + 320 * NS_PER_SEC,
true /* include current partial bucket */, true, ADB_DUMP, FAST,
&buffer);
- EXPECT_GT(buffer.size(), 0);
+ ASSERT_GT(buffer.size(), 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
StatsLogReport::DurationMetricDataWrapper durationMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
&durationMetrics);
- EXPECT_EQ(9, durationMetrics.data_size());
+ ASSERT_EQ(9, durationMetrics.data_size());
DurationMetricData data = durationMetrics.data(0);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
"wakelock1");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -1358,7 +1358,7 @@
data = durationMetrics.data(1);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
"wakelock1");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
@@ -1374,7 +1374,7 @@
data = durationMetrics.data(2);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
"wakelock2");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -1387,7 +1387,7 @@
data = durationMetrics.data(3);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
"wakelock2");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
@@ -1400,7 +1400,7 @@
data = durationMetrics.data(4);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock1");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value());
@@ -1412,7 +1412,7 @@
data = durationMetrics.data(5);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock1");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
@@ -1425,7 +1425,7 @@
data = durationMetrics.data(6);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock2");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value());
@@ -1437,7 +1437,7 @@
data = durationMetrics.data(7);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock2");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
@@ -1453,7 +1453,7 @@
data = durationMetrics.data(8);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock2");
- EXPECT_EQ(1, data.slice_by_state_size());
+ ASSERT_EQ(1, data.slice_by_state_size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index c234b14..1be2612 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -76,7 +76,7 @@
auto processor =
CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -87,7 +87,7 @@
// When creating the config, the gauge metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& nextPullTimeNs =
@@ -141,30 +141,30 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
- EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+ ASSERT_GT((int)gaugeMetrics.data_size(), 1);
auto data = gaugeMetrics.data(0);
EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(6, data.bucket_info_size());
+ ASSERT_EQ(6, data.bucket_info_size());
- EXPECT_EQ(1, data.bucket_info(0).atom_size());
- EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
@@ -172,32 +172,32 @@
EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(2).atom_size());
- EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(2).atom_size());
+ ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(3).atom_size());
- EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(3).atom_size());
+ ASSERT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, data.bucket_info(3).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(4).atom_size());
- EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(4).atom_size());
+ ASSERT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(4).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(5).atom_size());
- EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(5).atom_size());
+ ASSERT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, data.bucket_info(5).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
@@ -215,7 +215,7 @@
auto processor =
CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -259,30 +259,30 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
- EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+ ASSERT_GT((int)gaugeMetrics.data_size(), 1);
auto data = gaugeMetrics.data(0);
EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(3, data.bucket_info_size());
+ ASSERT_EQ(3, data.bucket_info_size());
- EXPECT_EQ(1, data.bucket_info(0).atom_size());
- EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, data.bucket_info(1).elapsed_timestamp_nanos(0));
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
@@ -290,8 +290,8 @@
EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(2, data.bucket_info(2).atom_size());
- EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(2, data.bucket_info(2).atom_size());
+ ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, data.bucket_info(2).elapsed_timestamp_nanos(1));
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
@@ -312,7 +312,7 @@
auto processor =
CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -323,7 +323,7 @@
// When creating the config, the gauge metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& nextPullTimeNs =
@@ -359,29 +359,29 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
- EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+ ASSERT_GT((int)gaugeMetrics.data_size(), 1);
auto data = gaugeMetrics.data(0);
EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(3, data.bucket_info_size());
+ ASSERT_EQ(3, data.bucket_info_size());
- EXPECT_EQ(1, data.bucket_info(0).atom_size());
- EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
data.bucket_info(1).elapsed_timestamp_nanos(0));
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
@@ -390,8 +390,8 @@
EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(2).atom_size());
- EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(2).atom_size());
+ ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, data.bucket_info(2).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
@@ -420,7 +420,7 @@
auto processor =
CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -432,7 +432,7 @@
// When creating the config, the gauge metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& nextPullTimeNs =
@@ -479,45 +479,45 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
- EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+ ASSERT_GT((int)gaugeMetrics.data_size(), 0);
auto data = gaugeMetrics.data(0);
EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(3, data.bucket_info_size());
+ ASSERT_EQ(3, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
- EXPECT_EQ(1, bucketInfo.atom_size());
- EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, bucketInfo.atom_size());
+ ASSERT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
bucketInfo = data.bucket_info(1);
- EXPECT_EQ(1, bucketInfo.atom_size());
- EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, bucketInfo.atom_size());
+ ASSERT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
bucketInfo = data.bucket_info(2);
- EXPECT_EQ(1, bucketInfo.atom_size());
- EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, bucketInfo.atom_size());
+ ASSERT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
bucketInfo.start_bucket_elapsed_nanos());
EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
@@ -538,7 +538,7 @@
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(),
ATOM_TAG);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -548,7 +548,7 @@
// When creating the config, the gauge metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& nextPullTimeNs =
@@ -572,43 +572,43 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(
reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
- EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+ ASSERT_GT((int)gaugeMetrics.data_size(), 0);
auto data = gaugeMetrics.data(0);
EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(3, data.bucket_info_size());
+ ASSERT_EQ(3, data.bucket_info_size());
- EXPECT_EQ(1, data.bucket_info(0).atom_size());
- EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(1).atom_size());
- EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
+ ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, data.bucket_info(1).wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, data.bucket_info(1).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
- EXPECT_EQ(1, data.bucket_info(2).atom_size());
- EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(2).atom_size());
+ ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 4, data.bucket_info(2).elapsed_timestamp_nanos(0));
- EXPECT_EQ(0, data.bucket_info(2).wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(0, data.bucket_info(2).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 60403f2..a40a948 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -103,7 +103,7 @@
ConfigKey cfgKey;
auto processor =
CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
int appUid1 = 123;
@@ -160,24 +160,24 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
&gaugeMetrics);
- EXPECT_EQ(2, gaugeMetrics.data_size());
+ ASSERT_EQ(2, gaugeMetrics.data_size());
auto data = gaugeMetrics.data(0);
EXPECT_EQ(util::APP_START_OCCURRED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(3, data.bucket_info_size());
+ ASSERT_EQ(3, data.bucket_info_size());
if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
- EXPECT_EQ(2, data.bucket_info(0).atom_size());
- EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
- EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ ASSERT_EQ(2, data.bucket_info(0).atom_size());
+ ASSERT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -194,8 +194,8 @@
EXPECT_EQ(103L,
data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
- EXPECT_EQ(1, data.bucket_info(1).atom_size());
- EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
+ ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -207,8 +207,8 @@
EXPECT_EQ(104L,
data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
- EXPECT_EQ(2, data.bucket_info(2).atom_size());
- EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(2, data.bucket_info(2).atom_size());
+ ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
@@ -226,8 +226,8 @@
EXPECT_EQ(106L,
data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
} else {
- EXPECT_EQ(1, data.bucket_info(0).atom_size());
- EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -238,8 +238,8 @@
EXPECT_EQ(102L,
data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
- EXPECT_EQ(1, data.bucket_info(1).atom_size());
- EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
+ ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -251,8 +251,8 @@
EXPECT_EQ(104L,
data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
- EXPECT_EQ(1, data.bucket_info(2).atom_size());
- EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info(2).atom_size());
+ ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
@@ -268,13 +268,13 @@
data = gaugeMetrics.data(1);
EXPECT_EQ(data.dimensions_in_what().field(), util::APP_START_OCCURRED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
- EXPECT_EQ(1, data.bucket_info(0).atom_size());
- EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ ASSERT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index ba8d283..e320419 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -267,10 +267,10 @@
processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
- EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
@@ -278,7 +278,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
- EXPECT_EQ(eventActivationMap.size(), 2u);
+ ASSERT_EQ(eventActivationMap.size(), 2u);
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
@@ -302,7 +302,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -353,7 +353,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 2);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -368,7 +368,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -389,42 +389,42 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(4, countMetrics.data_size());
+ ASSERT_EQ(4, countMetrics.data_size());
auto data = countMetrics.data(0);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(1);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(2);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
// Partial bucket as metric is deactivated.
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -433,11 +433,11 @@
data = countMetrics.data(3);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -478,10 +478,10 @@
processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
- EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
@@ -490,7 +490,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
- EXPECT_EQ(eventActivationMap.size(), 2u);
+ ASSERT_EQ(eventActivationMap.size(), 2u);
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
@@ -499,9 +499,9 @@
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
- EXPECT_EQ(eventDeactivationMap.size(), 1u);
+ ASSERT_EQ(eventDeactivationMap.size(), 1u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
- EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
std::unique_ptr<LogEvent> event;
@@ -518,7 +518,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -572,7 +572,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 2);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -588,7 +588,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -608,7 +608,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
@@ -628,7 +628,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
@@ -645,7 +645,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 4);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -663,7 +663,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 5);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
@@ -679,7 +679,7 @@
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 6);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -696,42 +696,42 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(5, countMetrics.data_size());
+ ASSERT_EQ(5, countMetrics.data_size());
auto data = countMetrics.data(0);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(1);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(2);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
// Partial bucket as metric is deactivated.
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -740,11 +740,11 @@
data = countMetrics.data(3);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -753,11 +753,11 @@
data = countMetrics.data(4);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -799,10 +799,10 @@
processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
- EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
@@ -811,7 +811,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
- EXPECT_EQ(eventActivationMap.size(), 2u);
+ ASSERT_EQ(eventActivationMap.size(), 2u);
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
@@ -820,11 +820,11 @@
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
- EXPECT_EQ(eventDeactivationMap.size(), 2u);
+ ASSERT_EQ(eventDeactivationMap.size(), 2u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
- EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
- EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[4].size(), 1u);
EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
@@ -842,7 +842,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -899,7 +899,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 2);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -916,7 +916,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -937,7 +937,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
@@ -959,7 +959,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 4);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -975,7 +975,7 @@
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 4);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -994,7 +994,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 5);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
@@ -1011,7 +1011,7 @@
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 6);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -1029,42 +1029,42 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(5, countMetrics.data_size());
+ ASSERT_EQ(5, countMetrics.data_size());
auto data = countMetrics.data(0);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(1);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(2);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
// Partial bucket as metric is deactivated.
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1073,11 +1073,11 @@
data = countMetrics.data(3);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1086,11 +1086,11 @@
data = countMetrics.data(4);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1132,10 +1132,10 @@
processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
- EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
@@ -1144,7 +1144,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
- EXPECT_EQ(eventActivationMap.size(), 2u);
+ ASSERT_EQ(eventActivationMap.size(), 2u);
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
@@ -1153,9 +1153,9 @@
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
- EXPECT_EQ(eventDeactivationMap.size(), 1u);
+ ASSERT_EQ(eventDeactivationMap.size(), 1u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
- EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
+ ASSERT_EQ(eventDeactivationMap[3].size(), 2u);
EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
EXPECT_EQ(broadcastCount, 0);
@@ -1172,7 +1172,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
@@ -1205,7 +1205,7 @@
EXPECT_FALSE(metricProducer->mIsActive);
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 2);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
@@ -1219,7 +1219,7 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
@@ -1236,7 +1236,7 @@
EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(broadcastCount, 4);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
@@ -1252,42 +1252,42 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(3, countMetrics.data_size());
+ ASSERT_EQ(3, countMetrics.data_size());
auto data = countMetrics.data(0);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(1);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(2);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
// Partial bucket as metric is deactivated.
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -1329,10 +1329,10 @@
processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
- EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
+ ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 2);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
@@ -1345,7 +1345,7 @@
EXPECT_FALSE(metricProducer2->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
- EXPECT_EQ(eventActivationMap.size(), 2u);
+ ASSERT_EQ(eventActivationMap.size(), 2u);
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
@@ -1354,15 +1354,15 @@
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
- EXPECT_EQ(eventDeactivationMap.size(), 2u);
+ ASSERT_EQ(eventDeactivationMap.size(), 2u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
- EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
- EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[4].size(), 1u);
EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
- EXPECT_EQ(eventActivationMap2.size(), 2u);
+ ASSERT_EQ(eventActivationMap2.size(), 2u);
EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
@@ -1371,11 +1371,11 @@
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
- EXPECT_EQ(eventDeactivationMap2.size(), 2u);
+ ASSERT_EQ(eventDeactivationMap2.size(), 2u);
EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
- EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
- EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
+ ASSERT_EQ(eventDeactivationMap[4].size(), 1u);
EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
@@ -1395,7 +1395,7 @@
processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
EXPECT_TRUE(metricsManager->isActive());
EXPECT_EQ(broadcastCount, 1);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -1487,7 +1487,7 @@
EXPECT_FALSE(metricsManager->isActive());
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 2);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
@@ -1513,7 +1513,7 @@
processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_TRUE(metricsManager->isActive());
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
@@ -1545,7 +1545,7 @@
processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_TRUE(metricsManager->isActive());
EXPECT_EQ(broadcastCount, 3);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -1578,7 +1578,7 @@
EXPECT_FALSE(metricsManager->isActive());
// New broadcast since the config is no longer active.
EXPECT_EQ(broadcastCount, 4);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
@@ -1605,7 +1605,7 @@
processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
EXPECT_FALSE(metricsManager->isActive());
EXPECT_EQ(broadcastCount, 4);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
@@ -1635,7 +1635,7 @@
processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_TRUE(metricsManager->isActive());
EXPECT_EQ(broadcastCount, 5);
- EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -1661,7 +1661,7 @@
processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
EXPECT_FALSE(metricsManager->isActive());
EXPECT_EQ(broadcastCount, 6);
- EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ ASSERT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
@@ -1689,43 +1689,43 @@
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(2, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(2, reports.reports(0).metrics_size());
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
- EXPECT_EQ(5, countMetrics.data_size());
+ ASSERT_EQ(5, countMetrics.data_size());
auto data = countMetrics.data(0);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(1);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(2);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
// Partial bucket as metric is deactivated.
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1734,11 +1734,11 @@
data = countMetrics.data(3);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1747,11 +1747,11 @@
data = countMetrics.data(4);
EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1760,37 +1760,37 @@
countMetrics.clear_data();
sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).count_metrics(), &countMetrics);
- EXPECT_EQ(5, countMetrics.data_size());
+ ASSERT_EQ(5, countMetrics.data_size());
data = countMetrics.data(0);
EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(1);
EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
data = countMetrics.data(2);
EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
// Partial bucket as metric is deactivated.
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1799,11 +1799,11 @@
data = countMetrics.data(3);
EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
@@ -1812,11 +1812,11 @@
data = countMetrics.data(4);
EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* uid field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
data.bucket_info(0).start_bucket_elapsed_nanos());
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index f0df2c6..5e77ee0 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -107,7 +107,7 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
int appUid = 123;
@@ -204,15 +204,15 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
auto data = reports.reports(0).metrics(0).count_metrics().data(0);
// Validate dimension value.
EXPECT_EQ(data.dimensions_in_what().field(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
// Uid field.
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
@@ -226,7 +226,7 @@
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
int appUid = 123;
@@ -324,16 +324,16 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
auto data = reports.reports(0).metrics(0).count_metrics().data(0);
// Validate dimension value.
EXPECT_EQ(data.dimensions_in_what().field(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
// Uid field.
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 9117623..783f31c 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -127,8 +127,8 @@
ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
// Expect no metrics since the bucket has not finished yet.
- EXPECT_EQ(1, report.metrics_size());
- EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(0, report.metrics(0).count_metrics().data_size());
}
TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
@@ -147,8 +147,8 @@
service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
- EXPECT_EQ(1, report.metrics_size());
- EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(0, report.metrics(0).count_metrics().data_size());
}
TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
@@ -267,8 +267,8 @@
GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
backfillStartEndTimestamp(&report);
- EXPECT_EQ(1, report.metrics_size());
- EXPECT_EQ(0, report.metrics(0).value_metrics().skipped_size());
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(0, report.metrics(0).value_metrics().skipped_size());
// The fake subsystem state sleep puller returns two atoms.
ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
@@ -305,7 +305,7 @@
report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
- EXPECT_EQ(1, report.metrics(0).value_metrics().data(0).bucket_info_size());
+ ASSERT_EQ(1, report.metrics(0).value_metrics().data(0).bucket_info_size());
}
TEST(PartialBucketE2eTest, TestValueMetricOnBootWithoutMinPartialBucket) {
@@ -329,7 +329,7 @@
// First bucket is dropped due to the initial pull failing
ASSERT_EQ(1, report.metrics_size());
- EXPECT_EQ(1, report.metrics(0).value_metrics().skipped_size());
+ ASSERT_EQ(1, report.metrics(0).value_metrics().skipped_size());
EXPECT_EQ(MillisToNano(NanoToMillis(bootCompleteTimeNs)),
report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
@@ -359,10 +359,10 @@
ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
backfillStartEndTimestamp(&report);
ASSERT_EQ(1, report.metrics_size());
- EXPECT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
+ ASSERT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
// The fake subsystem state sleep puller returns two atoms.
ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
- EXPECT_EQ(2, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
+ ASSERT_EQ(2, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
}
TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
@@ -391,7 +391,7 @@
EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
report.metrics(0).gauge_metrics().skipped(0).end_bucket_elapsed_nanos());
ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
- EXPECT_EQ(1, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
+ ASSERT_EQ(1, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
}
TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket) {
@@ -414,7 +414,7 @@
backfillStartEndTimestamp(&report);
ASSERT_EQ(1, report.metrics_size());
- EXPECT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
+ ASSERT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
// The fake subsystem state sleep puller returns two atoms.
ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
// No data in the first bucket, so nothing is reported
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 0c4a7c6..e595f29 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -75,7 +75,7 @@
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(),
util::SUBSYSTEM_SLEEP_STATE);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -86,7 +86,7 @@
// When creating the config, the value metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& expectedPullTimeNs =
@@ -136,36 +136,36 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::ValueMetricDataWrapper valueMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
- EXPECT_GT((int)valueMetrics.data_size(), 1);
+ ASSERT_GT((int)valueMetrics.data_size(), 1);
auto data = valueMetrics.data(0);
EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
// We have 4 buckets, the first one was incomplete since the condition was unknown.
- EXPECT_EQ(4, data.bucket_info_size());
+ ASSERT_EQ(4, data.bucket_info_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(0).values_size());
+ ASSERT_EQ(1, data.bucket_info(0).values_size());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(1).values_size());
+ ASSERT_EQ(1, data.bucket_info(1).values_size());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(2).values_size());
+ ASSERT_EQ(1, data.bucket_info(2).values_size());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(3).values_size());
+ ASSERT_EQ(1, data.bucket_info(3).values_size());
}
TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
@@ -179,7 +179,7 @@
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(),
util::SUBSYSTEM_SLEEP_STATE);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -190,7 +190,7 @@
// When creating the config, the value metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& expectedPullTimeNs =
@@ -244,31 +244,31 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::ValueMetricDataWrapper valueMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
- EXPECT_GT((int)valueMetrics.data_size(), 1);
+ ASSERT_GT((int)valueMetrics.data_size(), 1);
auto data = valueMetrics.data(0);
EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(3, data.bucket_info_size());
+ ASSERT_EQ(3, data.bucket_info_size());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(0).values_size());
+ ASSERT_EQ(1, data.bucket_info(0).values_size());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(1).values_size());
+ ASSERT_EQ(1, data.bucket_info(1).values_size());
EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(2).values_size());
+ ASSERT_EQ(1, data.bucket_info(2).values_size());
}
TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
@@ -291,7 +291,7 @@
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
SharedRefBase::make<FakeSubsystemSleepCallback>(),
util::SUBSYSTEM_SLEEP_STATE);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -303,7 +303,7 @@
// When creating the config, the value metric producer should register the alarm at the
// end of the current bucket.
- EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
int64_t& expectedPullTimeNs =
@@ -347,30 +347,30 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(1, reports.reports_size());
- EXPECT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::ValueMetricDataWrapper valueMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
- EXPECT_GT((int)valueMetrics.data_size(), 0);
+ ASSERT_GT((int)valueMetrics.data_size(), 0);
auto data = valueMetrics.data(0);
EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
- EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
// We have 2 full buckets, the two surrounding the activation are dropped.
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
auto bucketInfo = data.bucket_info(0);
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
- EXPECT_EQ(1, bucketInfo.values_size());
+ ASSERT_EQ(1, bucketInfo.values_size());
bucketInfo = data.bucket_info(1);
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
- EXPECT_EQ(1, bucketInfo.values_size());
+ ASSERT_EQ(1, bucketInfo.values_size());
}
/**
@@ -416,14 +416,14 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
// Check that ValueMetricProducer was initialized correctly.
- EXPECT_EQ(1U, processor->mMetricsManagers.size());
+ ASSERT_EQ(1U, processor->mMetricsManagers.size());
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(1, metricsManager->mAllMetricProducers.size());
+ ASSERT_EQ(1, metricsManager->mAllMetricProducers.size());
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
- EXPECT_EQ(1, metricProducer->mSlicedStateAtoms.size());
+ ASSERT_EQ(1, metricProducer->mSlicedStateAtoms.size());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, metricProducer->mSlicedStateAtoms.at(0));
- EXPECT_EQ(0, metricProducer->mStateGroupMap.size());
+ ASSERT_EQ(0, metricProducer->mStateGroupMap.size());
}
/**
@@ -476,14 +476,14 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
// Check that ValueMetricProducer was initialized correctly.
- EXPECT_EQ(1U, processor->mMetricsManagers.size());
+ ASSERT_EQ(1U, processor->mMetricsManagers.size());
sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
EXPECT_TRUE(metricsManager->isConfigValid());
- EXPECT_EQ(1, metricsManager->mAllMetricProducers.size());
+ ASSERT_EQ(1, metricsManager->mAllMetricProducers.size());
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
- EXPECT_EQ(1, metricProducer->mSlicedStateAtoms.size());
+ ASSERT_EQ(1, metricProducer->mSlicedStateAtoms.size());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, metricProducer->mSlicedStateAtoms.at(0));
- EXPECT_EQ(0, metricProducer->mStateGroupMap.size());
+ ASSERT_EQ(0, metricProducer->mStateGroupMap.size());
}
/**
@@ -532,7 +532,7 @@
EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount());
// Config initialization fails.
- EXPECT_EQ(0, processor->mMetricsManagers.size());
+ ASSERT_EQ(0, processor->mMetricsManagers.size());
}
#else
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 80f3c28..52bc222 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -121,7 +121,7 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
vector<uint8_t> buffer;
@@ -134,17 +134,17 @@
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
// Only 1 dimension output. The tag dimension in the predicate has been aggregated.
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
// Validate dimension value.
ValidateAttributionUidDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 111);
// Validate bucket info.
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
data = reports.reports(0).metrics(0).duration_metrics().data(0);
// The wakelock holding interval starts from the screen off event and to the end of the 1st
// bucket.
@@ -158,7 +158,7 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
vector<uint8_t> buffer;
@@ -170,11 +170,11 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
// Dump the report after the end of 2nd bucket.
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
// Validate dimension value.
ValidateAttributionUidDimension(data.dimensions_in_what(),
@@ -196,7 +196,7 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
vector<uint8_t> buffer;
@@ -222,10 +222,10 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
ValidateAttributionUidDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 111);
@@ -243,7 +243,7 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
ConfigMetricsReportList reports;
@@ -257,13 +257,13 @@
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
// When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
// one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
// itself.
- EXPECT_EQ(1, reports.reports(0).metrics_size());
- EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
}
TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
@@ -273,7 +273,7 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
ConfigMetricsReportList reports;
@@ -285,11 +285,11 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
// Dump the report after the end of 2nd bucket. One dimension with one bucket.
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
// Validate dimension value.
ValidateAttributionUidDimension(data.dimensions_in_what(),
@@ -305,7 +305,7 @@
uint64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
ConfigMetricsReportList reports;
@@ -331,10 +331,10 @@
backfillDimensionPath(&reports);
backfillStringInReport(&reports);
backfillStartEndTimestamp(&reports);
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
ValidateAttributionUidDimension(data.dimensions_in_what(),
util::WAKELOCK_STATE_CHANGED, 111);
diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
index 4b9bac1..13cdfc2 100644
--- a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
+++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
@@ -131,11 +131,11 @@
EXPECT_TRUE(puller.PullInternal(&dataHolder));
int64_t endTimeNs = getElapsedRealtimeNs();
- EXPECT_EQ(1, dataHolder.size());
+ ASSERT_EQ(1, dataHolder.size());
EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
EXPECT_LT(startTimeNs, dataHolder[0]->GetElapsedTimestampNs());
EXPECT_GT(endTimeNs, dataHolder[0]->GetElapsedTimestampNs());
- EXPECT_EQ(1, dataHolder[0]->size());
+ ASSERT_EQ(1, dataHolder[0]->size());
EXPECT_EQ(value, dataHolder[0]->getValues()[0].mValue.int_value);
}
@@ -149,13 +149,13 @@
vector<shared_ptr<LogEvent>> dataHolder;
EXPECT_FALSE(puller.PullInternal(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ ASSERT_EQ(0, dataHolder.size());
}
TEST_F(StatsCallbackPullerTest, PullTimeout) {
shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
pullSuccess = true;
- pullDelayNs = 500000000; // 500ms.
+ pullDelayNs = MillisToNano(5); // 5ms.
pullTimeoutNs = 10000; // 10 microseconds.
int64_t value = 4321;
values.push_back(value);
@@ -173,18 +173,18 @@
// is bigger.
EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
EXPECT_GT(pullDelayNs, actualPullDurationNs);
- EXPECT_EQ(0, dataHolder.size());
+ ASSERT_EQ(0, dataHolder.size());
// Let the pull return and make sure that the dataHolder is not modified.
pullThread.join();
- EXPECT_EQ(0, dataHolder.size());
+ ASSERT_EQ(0, dataHolder.size());
}
// Register a puller and ensure that the timeout logic works.
TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
pullSuccess = true;
- pullDelayNs = 500000000; // 500 ms.
+ pullDelayNs = MillisToNano(5); // 5 ms.
pullTimeoutNs = 10000; // 10 microsseconds.
int64_t value = 4321;
int32_t uid = 123;
@@ -196,7 +196,7 @@
vector<shared_ptr<LogEvent>> dataHolder;
int64_t startTimeNs = getElapsedRealtimeNs();
// Returns false, since StatsPuller code will evaluate the timeout.
- EXPECT_FALSE(pullerManager->Pull(pullTagId, {uid}, &dataHolder));
+ EXPECT_FALSE(pullerManager->Pull(pullTagId, {uid}, startTimeNs, &dataHolder));
int64_t endTimeNs = getElapsedRealtimeNs();
int64_t actualPullDurationNs = endTimeNs - startTimeNs;
@@ -204,11 +204,11 @@
// is bigger.
EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
EXPECT_GT(pullDelayNs, actualPullDurationNs);
- EXPECT_EQ(0, dataHolder.size());
+ ASSERT_EQ(0, dataHolder.size());
// Let the pull return and make sure that the dataHolder is not modified.
pullThread.join();
- EXPECT_EQ(0, dataHolder.size());
+ ASSERT_EQ(0, dataHolder.size());
}
} // namespace statsd
diff --git a/cmds/statsd/tests/external/StatsPullerManager_test.cpp b/cmds/statsd/tests/external/StatsPullerManager_test.cpp
index 6b3f4cc..c76e85e 100644
--- a/cmds/statsd/tests/external/StatsPullerManager_test.cpp
+++ b/cmds/statsd/tests/external/StatsPullerManager_test.cpp
@@ -101,14 +101,14 @@
sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
vector<shared_ptr<LogEvent>> data;
- EXPECT_FALSE(pullerManager->Pull(pullTagId1, {unregisteredUid}, &data, true));
+ EXPECT_FALSE(pullerManager->Pull(pullTagId1, {unregisteredUid}, /*timestamp =*/1, &data, true));
}
TEST(StatsPullerManagerTest, TestPullChoosesCorrectUid) {
sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
vector<shared_ptr<LogEvent>> data;
- EXPECT_TRUE(pullerManager->Pull(pullTagId1, {uid1}, &data, true));
+ EXPECT_TRUE(pullerManager->Pull(pullTagId1, {uid1}, /*timestamp =*/1, &data, true));
ASSERT_EQ(data.size(), 1);
EXPECT_EQ(data[0]->GetTagId(), pullTagId1);
ASSERT_EQ(data[0]->getValues().size(), 1);
@@ -121,7 +121,7 @@
pullerManager->RegisterPullUidProvider(configKey, uidProvider);
vector<shared_ptr<LogEvent>> data;
- EXPECT_FALSE(pullerManager->Pull(pullTagId1, badConfigKey, &data, true));
+ EXPECT_FALSE(pullerManager->Pull(pullTagId1, badConfigKey, /*timestamp =*/1, &data, true));
}
TEST(StatsPullerManagerTest, TestPullConfigKeyGood) {
@@ -130,7 +130,7 @@
pullerManager->RegisterPullUidProvider(configKey, uidProvider);
vector<shared_ptr<LogEvent>> data;
- EXPECT_TRUE(pullerManager->Pull(pullTagId1, configKey, &data, true));
+ EXPECT_TRUE(pullerManager->Pull(pullTagId1, configKey, /*timestamp =*/1, &data, true));
EXPECT_EQ(data[0]->GetTagId(), pullTagId1);
ASSERT_EQ(data[0]->getValues().size(), 1);
EXPECT_EQ(data[0]->getValues()[0].mValue.int_value, uid2);
@@ -142,7 +142,7 @@
pullerManager->RegisterPullUidProvider(configKey, uidProvider);
vector<shared_ptr<LogEvent>> data;
- EXPECT_FALSE(pullerManager->Pull(pullTagId2, configKey, &data, true));
+ EXPECT_FALSE(pullerManager->Pull(pullTagId2, configKey, /*timestamp =*/1, &data, true));
}
} // namespace statsd
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
index 5043358..55a9036 100644
--- a/cmds/statsd/tests/external/StatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/StatsPuller_test.cpp
@@ -39,7 +39,6 @@
using testing::Contains;
namespace {
-// cooldown time 1sec.
int pullTagId = 10014;
bool pullSuccess;
@@ -48,7 +47,8 @@
class FakePuller : public StatsPuller {
public:
- FakePuller() : StatsPuller(pullTagId, /*coolDown=*/NS_PER_SEC, /*timeout=*/NS_PER_SEC / 2){};
+ FakePuller()
+ : StatsPuller(pullTagId, /*coolDownNs=*/MillisToNano(10), /*timeoutNs=*/MillisToNano(5)){};
private:
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override {
@@ -92,25 +92,25 @@
pullSuccess = true;
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_TRUE(puller.Pull(&dataHolder));
- EXPECT_EQ(1, dataHolder.size());
+ EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
- EXPECT_EQ(1, dataHolder[0]->size());
+ ASSERT_EQ(1, dataHolder[0]->size());
EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
- sleep_for(std::chrono::seconds(1));
+ sleep_for(std::chrono::milliseconds(11));
pullData.clear();
pullData.push_back(createSimpleEvent(2222L, 44));
pullSuccess = true;
- EXPECT_TRUE(puller.Pull(&dataHolder));
- EXPECT_EQ(1, dataHolder.size());
+ EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
- EXPECT_EQ(1, dataHolder[0]->size());
+ ASSERT_EQ(1, dataHolder[0]->size());
EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
}
@@ -120,47 +120,49 @@
pullSuccess = true;
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_TRUE(puller.Pull(&dataHolder));
- EXPECT_EQ(1, dataHolder.size());
+ EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
- EXPECT_EQ(1, dataHolder[0]->size());
+ ASSERT_EQ(1, dataHolder[0]->size());
EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
- sleep_for(std::chrono::seconds(1));
+ sleep_for(std::chrono::milliseconds(11));
pullData.clear();
pullData.push_back(createSimpleEvent(2222L, 44));
pullSuccess = false;
dataHolder.clear();
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
+ // Fails due to hitting the cool down.
pullSuccess = true;
dataHolder.clear();
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
}
// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
pullData.push_back(createSimpleEvent(1111L, 33));
pullSuccess = true;
- // timeout is 0.5
- pullDelayNs = (long)(0.8 * NS_PER_SEC);
+ // timeout is 5ms
+ pullDelayNs = MillisToNano(6);
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
pullData.clear();
pullData.push_back(createSimpleEvent(2222L, 44));
+ pullDelayNs = 0;
pullSuccess = true;
dataHolder.clear();
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
}
TEST_F(StatsPullerTest, PullFail) {
@@ -169,19 +171,19 @@
pullSuccess = false;
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
}
TEST_F(StatsPullerTest, PullTakeTooLong) {
pullData.push_back(createSimpleEvent(1111L, 33));
pullSuccess = true;
- pullDelayNs = NS_PER_SEC;
+ pullDelayNs = MillisToNano(6);
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
}
TEST_F(StatsPullerTest, PullTooFast) {
@@ -190,11 +192,11 @@
pullSuccess = true;
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_TRUE(puller.Pull(&dataHolder));
- EXPECT_EQ(1, dataHolder.size());
+ EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
- EXPECT_EQ(1, dataHolder[0]->size());
+ ASSERT_EQ(1, dataHolder[0]->size());
EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
pullData.clear();
@@ -203,11 +205,11 @@
pullSuccess = true;
dataHolder.clear();
- EXPECT_TRUE(puller.Pull(&dataHolder));
- EXPECT_EQ(1, dataHolder.size());
+ EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
- EXPECT_EQ(1, dataHolder[0]->size());
+ ASSERT_EQ(1, dataHolder[0]->size());
EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
}
@@ -217,16 +219,93 @@
pullSuccess = false;
vector<std::shared_ptr<LogEvent>> dataHolder;
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
pullData.clear();
pullData.push_back(createSimpleEvent(2222L, 44));
pullSuccess = true;
- EXPECT_FALSE(puller.Pull(&dataHolder));
- EXPECT_EQ(0, dataHolder.size());
+ EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullSameEventTime) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+ int64_t eventTimeNs = getElapsedRealtimeNs();
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(eventTimeNs, &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ ASSERT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ // Sleep to ensure the cool down expires.
+ sleep_for(std::chrono::milliseconds(11));
+ pullSuccess = true;
+
+ dataHolder.clear();
+ EXPECT_TRUE(puller.Pull(eventTimeNs, &dataHolder));
+ ASSERT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ ASSERT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+// Test pull takes longer than timeout, 2nd pull happens at same event time
+TEST_F(StatsPullerTest, PullTakeTooLongAndPullSameEventTime) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+ pullSuccess = true;
+ int64_t eventTimeNs = getElapsedRealtimeNs();
+ // timeout is 5ms
+ pullDelayNs = MillisToNano(6);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
+
+ // Sleep to ensure the cool down expires. 6ms is taken by the delay, so only 5 is needed here.
+ sleep_for(std::chrono::milliseconds(5));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+ pullDelayNs = 0;
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullFailsAndPullSameEventTime) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+ int64_t eventTimeNs = getElapsedRealtimeNs();
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
+
+ // Sleep to ensure the cool down expires.
+ sleep_for(std::chrono::milliseconds(11));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
}
} // namespace statsd
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index cdde603..5cc10cd 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -42,7 +42,7 @@
StatsdStatsReport report;
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.config_stats_size());
+ ASSERT_EQ(1, report.config_stats_size());
const auto& configReport = report.config_stats(0);
EXPECT_EQ(0, configReport.uid());
EXPECT_EQ(12345, configReport.id());
@@ -69,7 +69,7 @@
StatsdStatsReport report;
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.config_stats_size());
+ ASSERT_EQ(1, report.config_stats_size());
const auto& configReport = report.config_stats(0);
// The invalid config should be put into icebox with a deletion time.
EXPECT_TRUE(configReport.has_deletion_time_sec());
@@ -89,7 +89,7 @@
StatsdStatsReport report;
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.config_stats_size());
+ ASSERT_EQ(1, report.config_stats_size());
const auto& configReport = report.config_stats(0);
EXPECT_FALSE(configReport.has_deletion_time_sec());
@@ -97,7 +97,7 @@
stats.dumpStats(&output, false);
good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.config_stats_size());
+ ASSERT_EQ(1, report.config_stats_size());
const auto& configReport2 = report.config_stats(0);
EXPECT_TRUE(configReport2.has_deletion_time_sec());
}
@@ -145,21 +145,21 @@
StatsdStatsReport report;
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.config_stats_size());
+ ASSERT_EQ(1, report.config_stats_size());
const auto& configReport = report.config_stats(0);
- EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
- EXPECT_EQ(1, configReport.data_drop_time_sec_size());
- EXPECT_EQ(1, configReport.data_drop_bytes_size());
+ ASSERT_EQ(2, configReport.broadcast_sent_time_sec_size());
+ ASSERT_EQ(1, configReport.data_drop_time_sec_size());
+ ASSERT_EQ(1, configReport.data_drop_bytes_size());
EXPECT_EQ(123, configReport.data_drop_bytes(0));
- EXPECT_EQ(3, configReport.dump_report_time_sec_size());
- EXPECT_EQ(3, configReport.dump_report_data_size_size());
- EXPECT_EQ(2, configReport.activation_time_sec_size());
- EXPECT_EQ(1, configReport.deactivation_time_sec_size());
- EXPECT_EQ(1, configReport.annotation_size());
+ ASSERT_EQ(3, configReport.dump_report_time_sec_size());
+ ASSERT_EQ(3, configReport.dump_report_data_size_size());
+ ASSERT_EQ(2, configReport.activation_time_sec_size());
+ ASSERT_EQ(1, configReport.deactivation_time_sec_size());
+ ASSERT_EQ(1, configReport.annotation_size());
EXPECT_EQ(123, configReport.annotation(0).field_int64());
EXPECT_EQ(456, configReport.annotation(0).field_int32());
- EXPECT_EQ(2, configReport.matcher_stats_size());
+ ASSERT_EQ(2, configReport.matcher_stats_size());
// matcher1 is the first in the list
if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
@@ -174,18 +174,18 @@
EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
}
- EXPECT_EQ(2, configReport.alert_stats_size());
+ ASSERT_EQ(2, configReport.alert_stats_size());
bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
- EXPECT_EQ(1, configReport.condition_stats_size());
+ ASSERT_EQ(1, configReport.condition_stats_size());
EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
- EXPECT_EQ(1, configReport.metric_stats_size());
+ ASSERT_EQ(1, configReport.metric_stats_size());
EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
@@ -199,21 +199,21 @@
stats.dumpStats(&output, false);
good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.config_stats_size());
+ ASSERT_EQ(1, report.config_stats_size());
const auto& configReport2 = report.config_stats(0);
- EXPECT_EQ(1, configReport2.matcher_stats_size());
+ ASSERT_EQ(1, configReport2.matcher_stats_size());
EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
- EXPECT_EQ(1, configReport2.condition_stats_size());
+ ASSERT_EQ(1, configReport2.condition_stats_size());
EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
- EXPECT_EQ(1, configReport2.metric_stats_size());
+ ASSERT_EQ(1, configReport2.metric_stats_size());
EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
- EXPECT_EQ(1, configReport2.alert_stats_size());
+ ASSERT_EQ(1, configReport2.alert_stats_size());
EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
}
@@ -234,7 +234,7 @@
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(2, report.atom_stats_size());
+ ASSERT_EQ(2, report.atom_stats_size());
bool sensorAtomGood = false;
bool dropboxAtomGood = false;
@@ -267,7 +267,7 @@
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(2, report.atom_stats_size());
+ ASSERT_EQ(2, report.atom_stats_size());
bool newAtom1Good = false;
bool newAtom2Good = false;
@@ -302,7 +302,10 @@
stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, false);
stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
-
+ stats.notePullBinderCallFailed(util::DISK_SPACE);
+ stats.notePullUidProviderNotFound(util::DISK_SPACE);
+ stats.notePullerNotFound(util::DISK_SPACE);
+ stats.notePullerNotFound(util::DISK_SPACE);
vector<uint8_t> output;
stats.dumpStats(&output, false);
@@ -310,7 +313,7 @@
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(1, report.pulled_atom_stats_size());
+ ASSERT_EQ(1, report.pulled_atom_stats_size());
EXPECT_EQ(util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
EXPECT_EQ(3, report.pulled_atom_stats(0).total_pull());
@@ -322,6 +325,9 @@
EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
+ EXPECT_EQ(1L, report.pulled_atom_stats(0).binder_call_failed());
+ EXPECT_EQ(1L, report.pulled_atom_stats(0).failed_uid_provider_not_found());
+ EXPECT_EQ(2L, report.pulled_atom_stats(0).puller_not_found());
}
TEST(StatsdStatsTest, TestAtomMetricsStats) {
@@ -342,7 +348,7 @@
bool good = report.ParseFromArray(&output[0], output.size());
EXPECT_TRUE(good);
- EXPECT_EQ(2, report.atom_metric_stats().size());
+ ASSERT_EQ(2, report.atom_metric_stats().size());
auto atomStats = report.atom_metric_stats(0);
EXPECT_EQ(1000L, atomStats.metric_id());
@@ -401,11 +407,11 @@
const auto& configStats = stats.mConfigStats[key];
size_t maxCount = StatsdStats::kMaxTimestampCount;
- EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
- EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
- EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
- EXPECT_EQ(maxCount, configStats->activation_time_sec.size());
- EXPECT_EQ(maxCount, configStats->deactivation_time_sec.size());
+ ASSERT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
+ ASSERT_EQ(maxCount, configStats->data_drop_time_sec.size());
+ ASSERT_EQ(maxCount, configStats->dump_report_stats.size());
+ ASSERT_EQ(maxCount, configStats->activation_time_sec.size());
+ ASSERT_EQ(maxCount, configStats->deactivation_time_sec.size());
// the oldest timestamp is the second timestamp in history
EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
@@ -435,13 +441,13 @@
StatsdStatsReport report;
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
const int maxCount = StatsdStats::kMaxSystemServerRestarts;
- EXPECT_EQ(maxCount, (int)report.system_restart_sec_size());
+ ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
output.clear();
stats.dumpStats(&output, false);
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
- EXPECT_EQ(maxCount, (int)report.system_restart_sec_size());
+ ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
}
@@ -462,19 +468,19 @@
StatsdStatsReport report;
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
- EXPECT_EQ(2, report.activation_guardrail_stats_size());
+ ASSERT_EQ(2, report.activation_guardrail_stats_size());
bool uid1Good = false;
bool uid2Good = false;
for (const auto& guardrailTimes : report.activation_guardrail_stats()) {
if (uid1 == guardrailTimes.uid()) {
uid1Good = true;
- EXPECT_EQ(2, guardrailTimes.guardrail_met_sec_size());
+ ASSERT_EQ(2, guardrailTimes.guardrail_met_sec_size());
EXPECT_EQ(10, guardrailTimes.guardrail_met_sec(0));
EXPECT_EQ(20, guardrailTimes.guardrail_met_sec(1));
} else if (uid2 == guardrailTimes.uid()) {
int maxCount = StatsdStats::kMaxTimestampCount;
uid2Good = true;
- EXPECT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
+ ASSERT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
for (int i = 0; i < maxCount; i++) {
EXPECT_EQ(100 - maxCount + i, guardrailTimes.guardrail_met_sec(i));
}
@@ -509,13 +515,13 @@
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
// Check error count = numErrors for push atom
- EXPECT_EQ(1, report.atom_stats_size());
+ ASSERT_EQ(1, report.atom_stats_size());
const auto& pushedAtomStats = report.atom_stats(0);
EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
EXPECT_EQ(numErrors, pushedAtomStats.error_count());
// Check error count = numErrors for pull atom
- EXPECT_EQ(1, report.pulled_atom_stats_size());
+ ASSERT_EQ(1, report.pulled_atom_stats_size());
const auto& pulledAtomStats = report.pulled_atom_stats(0);
EXPECT_EQ(pullAtomTag, pulledAtomStats.atom_id());
EXPECT_EQ(numErrors, pulledAtomStats.atom_error_count());
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
index d6cd876..3a65456 100644
--- a/cmds/statsd/tests/indexed_priority_queue_test.cpp
+++ b/cmds/statsd/tests/indexed_priority_queue_test.cpp
@@ -44,23 +44,23 @@
sp<const AATest> aa4 = new AATest{4, emptyMetricId, emptyDimensionId};
sp<const AATest> aa8 = new AATest{8, emptyMetricId, emptyDimensionId};
- EXPECT_EQ(0u, ipq.size());
+ ASSERT_EQ(0u, ipq.size());
EXPECT_TRUE(ipq.empty());
ipq.push(aa4);
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_FALSE(ipq.empty());
ipq.push(aa8);
- EXPECT_EQ(2u, ipq.size());
+ ASSERT_EQ(2u, ipq.size());
EXPECT_FALSE(ipq.empty());
ipq.remove(aa4);
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_FALSE(ipq.empty());
ipq.remove(aa8);
- EXPECT_EQ(0u, ipq.size());
+ ASSERT_EQ(0u, ipq.size());
EXPECT_TRUE(ipq.empty());
}
@@ -126,17 +126,17 @@
sp<const AATest> aa4_b = new AATest{4, emptyMetricId, emptyDimensionId};
ipq.push(aa4_a);
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_TRUE(ipq.contains(aa4_a));
EXPECT_FALSE(ipq.contains(aa4_b));
ipq.push(aa4_a);
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_TRUE(ipq.contains(aa4_a));
EXPECT_FALSE(ipq.contains(aa4_b));
ipq.push(aa4_b);
- EXPECT_EQ(2u, ipq.size());
+ ASSERT_EQ(2u, ipq.size());
EXPECT_TRUE(ipq.contains(aa4_a));
EXPECT_TRUE(ipq.contains(aa4_b));
}
@@ -150,7 +150,7 @@
ipq.push(aa4);
ipq.remove(aa5);
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_TRUE(ipq.contains(aa4));
EXPECT_FALSE(ipq.contains(aa5));
}
@@ -164,17 +164,17 @@
ipq.push(aa4_a);
ipq.push(aa4_b);
- EXPECT_EQ(2u, ipq.size());
+ ASSERT_EQ(2u, ipq.size());
EXPECT_TRUE(ipq.contains(aa4_a));
EXPECT_TRUE(ipq.contains(aa4_b));
ipq.remove(aa4_b);
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_TRUE(ipq.contains(aa4_a));
EXPECT_FALSE(ipq.contains(aa4_b));
ipq.remove(aa4_a);
- EXPECT_EQ(0u, ipq.size());
+ ASSERT_EQ(0u, ipq.size());
EXPECT_FALSE(ipq.contains(aa4_a));
EXPECT_FALSE(ipq.contains(aa4_b));
}
@@ -205,22 +205,22 @@
ipq.push(c);
ipq.push(b);
ipq.push(a);
- EXPECT_EQ(3u, ipq.size());
+ ASSERT_EQ(3u, ipq.size());
ipq.pop();
- EXPECT_EQ(2u, ipq.size());
+ ASSERT_EQ(2u, ipq.size());
EXPECT_FALSE(ipq.contains(a));
EXPECT_TRUE(ipq.contains(b));
EXPECT_TRUE(ipq.contains(c));
ipq.pop();
- EXPECT_EQ(1u, ipq.size());
+ ASSERT_EQ(1u, ipq.size());
EXPECT_FALSE(ipq.contains(a));
EXPECT_FALSE(ipq.contains(b));
EXPECT_TRUE(ipq.contains(c));
ipq.pop();
- EXPECT_EQ(0u, ipq.size());
+ ASSERT_EQ(0u, ipq.size());
EXPECT_FALSE(ipq.contains(a));
EXPECT_FALSE(ipq.contains(b));
EXPECT_FALSE(ipq.contains(c));
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 8131725..74ecaac 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -108,15 +108,15 @@
// Flushes at event #2.
countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
- EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
// Flushes.
countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets.size());
+ ASSERT_EQ(1UL, buckets.size());
EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
EXPECT_EQ(2LL, buckets[0].mCount);
@@ -128,10 +128,10 @@
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
- EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
- EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
@@ -139,11 +139,11 @@
// nothing happens in bucket 3. we should not record anything for bucket 3.
countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
- EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(2UL, buckets3.size());
+ ASSERT_EQ(2UL, buckets3.size());
}
TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
@@ -166,7 +166,7 @@
makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
- EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
@@ -174,15 +174,15 @@
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
- EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets.size());
+ ASSERT_EQ(1UL, buckets.size());
const auto& bucketInfo = buckets[0];
EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
@@ -229,15 +229,15 @@
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
- EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
countProducer.mPastBuckets.end());
const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets.size());
+ ASSERT_EQ(1UL, buckets.size());
const auto& bucketInfo = buckets[0];
EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
@@ -271,7 +271,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
- EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
// App upgrade or boot complete forces bucket flush.
@@ -284,7 +284,7 @@
countProducer.onStatsdInitCompleted(eventTimeNs);
break;
}
- EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs,
countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
EXPECT_EQ(eventTimeNs,
@@ -299,7 +299,7 @@
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
- EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(0, countProducer.getCurrentBucketNum());
EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
@@ -308,7 +308,7 @@
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
- EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(1, countProducer.getCurrentBucketNum());
EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
@@ -334,7 +334,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
- EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
// App upgrade or boot complete forces bucket flush.
// Check that there's a past bucket and the bucket end is not adjusted since the upgrade
@@ -347,7 +347,7 @@
countProducer.onStatsdInitCompleted(eventTimeNs);
break;
}
- EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs,
countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
@@ -358,13 +358,13 @@
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
- EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
// Third event in following bucket.
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
- EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ((int64_t)eventTimeNs,
countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -416,13 +416,13 @@
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
- EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
// One event in bucket #2. No alarm as bucket #0 is trashed out.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
- EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
@@ -430,14 +430,14 @@
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
- EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
// Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
- EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 8ef2519..ddda71d 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -104,11 +104,11 @@
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
- EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, durationProducer.mPastBuckets.size());
EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
durationProducer.mPastBuckets.end());
const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(2UL, buckets.size());
+ ASSERT_EQ(2UL, buckets.size());
EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
@@ -150,17 +150,17 @@
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
- EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, durationProducer.mPastBuckets.size());
EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
durationProducer.mPastBuckets.end());
const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets2.size());
+ ASSERT_EQ(1UL, buckets2.size());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
EXPECT_EQ(1LL, buckets2[0].mDuration);
@@ -198,15 +198,15 @@
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
- EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, durationProducer.mPastBuckets.size());
const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets2.size());
+ ASSERT_EQ(1UL, buckets2.size());
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
EXPECT_EQ(1LL, buckets2[0].mDuration);
@@ -241,7 +241,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, startTimeNs, tagId);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
@@ -253,7 +253,7 @@
durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
break;
}
- EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
std::vector<DurationBucket> buckets =
durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
@@ -268,7 +268,7 @@
makeLogEvent(&event2, endTimeNs, tagId);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(3UL, buckets.size());
+ ASSERT_EQ(3UL, buckets.size());
EXPECT_EQ(partialBucketSplitTimeNs, buckets[1].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - partialBucketSplitTimeNs, buckets[1].mDuration);
@@ -303,7 +303,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, startTimeNs, tagId);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
@@ -315,7 +315,7 @@
durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
break;
}
- EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
std::vector<DurationBucket> buckets =
durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
@@ -333,7 +333,7 @@
makeLogEvent(&event2, endTimeNs, tagId);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(3UL, buckets.size());
+ ASSERT_EQ(3UL, buckets.size());
EXPECT_EQ(partialBucketSplitTimeNs, buckets[2].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - partialBucketSplitTimeNs,
@@ -411,7 +411,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, startTimeNs, tagId);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
@@ -423,7 +423,7 @@
durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
break;
}
- EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(0, durationProducer.getCurrentBucketNum());
@@ -432,12 +432,12 @@
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event2, endTimeNs, tagId);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
std::vector<DurationBucket> buckets =
durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets.size());
+ ASSERT_EQ(1UL, buckets.size());
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
@@ -464,7 +464,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event1, startTimeNs, tagId);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
@@ -476,7 +476,7 @@
durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
break;
}
- EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(1, durationProducer.getCurrentBucketNum());
@@ -485,13 +485,13 @@
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeLogEvent(&event2, endTimeNs, tagId);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
- EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
std::vector<DurationBucket> buckets =
durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
- EXPECT_EQ(1UL, buckets.size());
+ ASSERT_EQ(1UL, buckets.size());
EXPECT_EQ(partialBucketSplitTimeNs, buckets[0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 97647a7..5bae364 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -79,7 +79,7 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_event_metrics());
- EXPECT_EQ(2, report.event_metrics().data_size());
+ ASSERT_EQ(2, report.event_metrics().data_size());
EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos());
}
@@ -118,7 +118,7 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_event_metrics());
- EXPECT_EQ(1, report.event_metrics().data_size());
+ ASSERT_EQ(1, report.event_metrics().data_size());
EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
}
@@ -168,7 +168,7 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_event_metrics());
- EXPECT_EQ(1, report.event_metrics().data_size());
+ ASSERT_EQ(1, report.event_metrics().data_size());
EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos());
}
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 9d2ec88..cc5f459 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -138,11 +138,12 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
data->clear();
- data->push_back(makeLogEvent(tagId, bucketStartTimeNs + 10, 3, "some value", 11));
+ data->push_back(makeLogEvent(tagId, eventTimeNs + 10, 3, "some value", 11));
return true;
}));
@@ -156,13 +157,13 @@
allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
EXPECT_EQ(INT, it->mValue.getType());
EXPECT_EQ(10, it->mValue.int_value);
it++;
EXPECT_EQ(11, it->mValue.int_value);
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
->second.back()
.mGaugeAtoms.front()
@@ -172,7 +173,7 @@
allData.clear();
allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
EXPECT_EQ(INT, it->mValue.getType());
EXPECT_EQ(24, it->mValue.int_value);
@@ -180,8 +181,8 @@
EXPECT_EQ(INT, it->mValue.getType());
EXPECT_EQ(25, it->mValue.int_value);
// One dimension.
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
EXPECT_EQ(INT, it->mValue.getType());
EXPECT_EQ(10L, it->mValue.int_value);
@@ -190,10 +191,10 @@
EXPECT_EQ(11L, it->mValue.int_value);
gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
- EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
// One dimension.
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
- EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
EXPECT_EQ(INT, it->mValue.getType());
EXPECT_EQ(24L, it->mValue.int_value);
@@ -247,7 +248,7 @@
break;
}
EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs,
gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
EXPECT_EQ(partialBucketSplitTimeNs,
@@ -262,7 +263,7 @@
CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs,
gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
EXPECT_EQ(partialBucketSplitTimeNs,
@@ -277,7 +278,7 @@
CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
- EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
@@ -286,7 +287,7 @@
CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
- EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
}
@@ -311,15 +312,15 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
.WillOnce(Return(false))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(
- CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 2));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 2));
+ return true;
+ }));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
@@ -329,7 +330,7 @@
vector<shared_ptr<LogEvent>> allData;
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -343,14 +344,14 @@
gaugeProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
break;
}
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs,
gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
EXPECT_EQ(partialBucketSplitTimeNs,
gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
EXPECT_EQ(partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -359,8 +360,8 @@
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -389,7 +390,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Return(false));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
@@ -399,17 +401,17 @@
vector<shared_ptr<LogEvent>> allData;
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
->mValue.int_value);
gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
- EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -435,14 +437,16 @@
new EventMatcherWizard({new SimpleLogMatchingTracker(
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ int64_t conditionChangeNs = bucketStartTimeNs + 8;
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, conditionChangeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 100));
+ data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs + 10, 100));
return true;
}));
@@ -451,25 +455,25 @@
bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
- gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ gaugeProducer.onConditionChanged(true, conditionChangeNs);
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
->mValue.int_value);
- EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, gaugeProducer.mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
->mValue.int_value);
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
->second.back()
.mGaugeAtoms.front()
@@ -478,8 +482,8 @@
gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
->second.back()
.mGaugeAtoms.front()
@@ -519,14 +523,16 @@
return ConditionState::kTrue;
}));
+ int64_t sliceConditionChangeNs = bucketStartTimeNs + 8;
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, sliceConditionChangeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 1000, 100));
+ data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs + 10, 1000, 100));
return true;
}));
@@ -535,22 +541,22 @@
bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
- gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
+ gaugeProducer.onSlicedConditionMayChange(true, sliceConditionChangeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
- EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(0UL, gaugeProducer.mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
}
TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
@@ -560,7 +566,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Return(false));
GaugeMetric metric;
metric.set_id(metricId);
@@ -596,7 +603,7 @@
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -609,7 +616,7 @@
allData.clear();
allData.push_back(event2);
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -621,7 +628,7 @@
allData.push_back(
CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
@@ -633,7 +640,7 @@
allData.clear();
allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10));
gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
}
@@ -658,17 +665,19 @@
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 4));
+ data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 4));
return true;
}))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 5));
+ data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
return true;
}))
.WillOnce(Return(true));
@@ -679,20 +688,20 @@
tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
- EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
+ ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
->second.back()
.mGaugeAtoms[0]
@@ -727,23 +736,26 @@
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 3, 3, 4));
- return true;
- }))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5));
+ data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 3, 4));
return true;
}))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 4, 6));
+ data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 4, 5));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 4, 6));
return true;
}))
.WillOnce(Return(true));
@@ -757,24 +769,24 @@
LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
+ ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
- EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
+ ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.size());
auto bucketIt = gaugeProducer.mPastBuckets.begin();
- EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
+ ASSERT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
bucketIt++;
- EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
+ ASSERT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
@@ -801,14 +813,14 @@
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 3, _, _))
// Bucket start.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 10));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 10));
+ return true;
+ }));
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
@@ -828,14 +840,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_gauge_metrics());
- EXPECT_EQ(0, report.gauge_metrics().data_size());
- EXPECT_EQ(1, report.gauge_metrics().skipped_size());
+ ASSERT_EQ(0, report.gauge_metrics().data_size());
+ ASSERT_EQ(1, report.gauge_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index d2f0f57..fda3daa 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -77,7 +77,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(20LL, buckets[eventKey][0].mDuration);
}
@@ -110,7 +110,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(bucketSizeNs + 40 - 1, buckets[eventKey][0].mDuration);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[eventKey][0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[eventKey][0].mBucketEndNs);
@@ -149,7 +149,7 @@
EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
tracker.flushIfNeeded(bucketStartTimeNs + 4 * bucketSizeNs, &buckets);
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ((3 * bucketSizeNs) + 20 - 1, buckets[eventKey][0].mDuration);
EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[eventKey][0].mBucketStartNs);
EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, buckets[eventKey][0].mBucketEndNs);
@@ -187,7 +187,7 @@
bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1, &buckets);
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(2 * bucketSizeNs + 5 - 1, buckets[eventKey][0].mDuration);
}
@@ -223,15 +223,15 @@
tracker.noteConditionChanged(key1, false, conditionStops1);
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
- EXPECT_EQ(0U, buckets.size());
+ ASSERT_EQ(0U, buckets.size());
tracker.noteConditionChanged(key1, true, conditionStarts2);
tracker.noteConditionChanged(key1, false, conditionStops2);
tracker.noteStop(key1, eventStopTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 1, &buckets);
- EXPECT_EQ(1U, buckets.size());
+ ASSERT_EQ(1U, buckets.size());
vector<DurationBucket> item = buckets.begin()->second;
- EXPECT_EQ(1UL, item.size());
+ ASSERT_EQ(1UL, item.size());
EXPECT_EQ((int64_t)(13LL * NS_PER_SEC), item[0].mDuration);
}
@@ -272,11 +272,11 @@
// Remove the anomaly alarm when the duration is no longer fully met.
tracker.noteConditionChanged(key1, false, eventStartTimeNs + 15 * NS_PER_SEC);
- EXPECT_EQ(0U, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(0U, anomalyTracker->mAlarms.size());
// Since the condition was off for 10 seconds, the anomaly should trigger 10 sec later.
tracker.noteConditionChanged(key1, true, eventStartTimeNs + 25 * NS_PER_SEC);
- EXPECT_EQ(1U, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(63ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
}
@@ -330,7 +330,7 @@
tracker.noteConditionChanged(key1, false, conditionStops1);
tracker.noteStart(key2, true, eventStartTimeNs2, conditionKey2); // Condition is on already.
tracker.noteConditionChanged(key1, true, conditionStarts2);
- EXPECT_EQ(1U, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
auto alarm = anomalyTracker->mAlarms.begin()->second;
int64_t anomalyFireTimeSec = alarm->timestampSec;
EXPECT_EQ(conditionStarts2 + 36 * NS_PER_SEC,
@@ -341,7 +341,7 @@
// gets correctly taken into account in future predictAnomalyTimestampNs calculations.
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarms({alarm});
anomalyTracker->informAlarmsFired(anomalyFireTimeSec * NS_PER_SEC, firedAlarms);
- EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
int64_t refractoryPeriodEndsSec = anomalyFireTimeSec + refPeriodSec;
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), refractoryPeriodEndsSec);
@@ -352,7 +352,7 @@
tracker.noteStop(key2, eventStopTimeNs, false);
tracker.noteStart(key1, true, eventStopTimeNs + 1000000, conditionKey1);
// Anomaly is ongoing, but we're still in the refractory period.
- EXPECT_EQ(1U, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ(refractoryPeriodEndsSec, (long long)(alarm->timestampSec));
@@ -410,7 +410,7 @@
tracker.noteStart(key1, true, eventStartTimeNs1, conditionKey1);
tracker.noteStart(key2, true, eventStartTimeNs2, conditionKey2);
tracker.noteStop(key1, eventStopTimeNs1, false);
- EXPECT_EQ(1U, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
auto alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ(eventStopTimeNs1 + 35 * NS_PER_SEC,
(unsigned long long)(alarm->timestampSec * NS_PER_SEC));
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 39d3919..1d6f7de 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -74,7 +74,7 @@
tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
}
@@ -103,7 +103,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(2003LL, buckets[eventKey][0].mDuration);
}
@@ -133,7 +133,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(2003LL, buckets[eventKey][0].mDuration);
}
@@ -161,7 +161,7 @@
tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2 * bucketSizeNs, ConditionKey());
EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
- EXPECT_EQ(2u, buckets[eventKey].size());
+ ASSERT_EQ(2u, buckets[eventKey].size());
EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
@@ -169,7 +169,7 @@
tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 12, false);
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(2u, buckets[eventKey].size());
+ ASSERT_EQ(2u, buckets[eventKey].size());
EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
}
@@ -207,7 +207,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(5LL, buckets[eventKey][0].mDuration);
}
@@ -248,7 +248,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(1005LL, buckets[eventKey][0].mDuration);
}
@@ -286,7 +286,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(15LL, buckets[eventKey][0].mDuration);
}
@@ -322,7 +322,7 @@
tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 3, false);
- EXPECT_EQ(0u, buckets[eventKey].size());
+ ASSERT_EQ(0u, buckets[eventKey].size());
int64_t event1StartTimeNs = eventStartTimeNs + 10;
tracker.noteStart(kEventKey1, true, event1StartTimeNs, ConditionKey());
@@ -335,7 +335,7 @@
tracker.noteStop(kEventKey1, event1StopTimeNs, false);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
- EXPECT_EQ(1u, buckets[eventKey].size());
+ ASSERT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(3LL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
buckets[eventKey][0].mDuration);
@@ -486,10 +486,10 @@
EXPECT_TRUE(tracker.mStarted.empty());
EXPECT_EQ(10LL, tracker.mStateKeyDurationMap[DEFAULT_DIMENSION_KEY].mDuration); // 10ns
- EXPECT_EQ(0u, tracker.mStarted.size());
+ ASSERT_EQ(0u, tracker.mStarted.size());
tracker.noteStart(kEventKey1, true, eventStartTimeNs + 20, ConditionKey());
- EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
EXPECT_EQ((long long)(52ULL * NS_PER_SEC), // (10s + 1s + 1ns + 20ns) - 10ns + 40s, rounded up
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
// The alarm is set to fire at 52s, and when it does, an anomaly would be declared. However,
@@ -530,29 +530,29 @@
false, {anomalyTracker});
tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1
- EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(55ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
tracker.noteStop(kEventKey1, 17 * NS_PER_SEC, false); // stop key1 (2 seconds later)
- EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
tracker.noteStart(kEventKey1, true, 22 * NS_PER_SEC, conkey); // start key1 again
- EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
tracker.noteStart(kEventKey2, true, 32 * NS_PER_SEC, conkey); // start key2
- EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
tracker.noteStop(kEventKey1, 47 * NS_PER_SEC, false); // stop key1
- EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
@@ -560,11 +560,11 @@
// Now, at 60s, which is 38s after key1 started again, we have reached 40s of 'on' time.
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarms({alarm});
anomalyTracker->informAlarmsFired(62 * NS_PER_SEC, firedAlarms);
- EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
tracker.noteStop(kEventKey2, 69 * NS_PER_SEC, false); // stop key2
- EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
+ ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
}
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index f493cc4..474aa22 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -278,13 +278,13 @@
TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
- return true;
- }));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
@@ -295,7 +295,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -304,7 +304,7 @@
EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
@@ -312,7 +312,7 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -320,8 +320,8 @@
EXPECT_EQ(23, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(12, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
@@ -330,7 +330,7 @@
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -338,8 +338,8 @@
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(13, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
@@ -352,18 +352,20 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2;
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Initialize bucket.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
return true;
}))
// Partial bucket.
- .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
- vector<std::shared_ptr<LogEvent>>* data,
- bool) {
+ .WillOnce(Invoke([partialBucketSplitTimeNs](
+ int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
data->clear();
data->push_back(
CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs + 8, 5));
@@ -416,13 +418,13 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 3, 3));
- return true;
- }));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 3, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, logEventMatcherIndex,
@@ -435,7 +437,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -444,7 +446,7 @@
EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
@@ -452,20 +454,20 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket3StartTimeNs + 1, 4, 23));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// No new data seen, so data has been cleared.
- EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -473,8 +475,8 @@
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
}
@@ -487,7 +489,8 @@
metric.set_use_absolute_value_on_reset(true);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(true));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Return(true));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
@@ -497,7 +500,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -505,35 +508,35 @@
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(26, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
@@ -546,7 +549,8 @@
TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Return(false));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
@@ -556,7 +560,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -564,31 +568,31 @@
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(26, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
}
@@ -601,21 +605,24 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); // First condition change.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
return true;
}))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1); // Second condition change.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 130));
return true;
}))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 1); // Third condition change.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 180));
return true;
@@ -627,7 +634,7 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -635,7 +642,7 @@
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -645,7 +652,7 @@
{bucketStartTimeNs}, {bucket2StartTimeNs});
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -658,7 +665,7 @@
{bucketStartTimeNs}, {bucket2StartTimeNs});
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
@@ -690,7 +697,7 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 150;
switch (GetParam()) {
@@ -745,11 +752,12 @@
int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 150;
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
.WillOnce(Return(true))
- .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
- vector<std::shared_ptr<LogEvent>>* data,
- bool) {
+ .WillOnce(Invoke([partialBucketSplitTimeNs](
+ int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 120));
return true;
@@ -764,7 +772,7 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
switch (GetParam()) {
case APP_UPGRADE:
@@ -803,7 +811,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(true));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Return(true));
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
@@ -814,10 +823,10 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ ASSERT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
}
@@ -825,15 +834,18 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1); // Condition change to true time.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
return true;
}))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs,
+ bucket2StartTimeNs - 100); // Condition change to false time.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs - 100, 120));
return true;
@@ -888,7 +900,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
@@ -898,7 +910,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(30, curInterval.value.long_value);
@@ -929,7 +941,7 @@
CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has 1 slice
- EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
@@ -938,7 +950,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
@@ -949,7 +961,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(50, curInterval.value.long_value);
@@ -960,7 +972,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(50, curInterval.value.long_value);
@@ -1049,7 +1061,8 @@
TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(true));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Return(true));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
@@ -1060,7 +1073,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -1069,14 +1082,14 @@
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
// pull 2 at correct time
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// tartUpdated:false sum:12
@@ -1093,7 +1106,7 @@
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// startUpdated:false sum:12
@@ -1119,17 +1132,19 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); // First condition change.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
return true;
}))
// condition becomes false
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1); // Second condition change.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
return true;
@@ -1140,14 +1155,14 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
@@ -1179,24 +1194,27 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
return true;
}))
// condition becomes false
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
return true;
}))
// condition becomes true again
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 25);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 25, 130));
return true;
@@ -1208,7 +1226,7 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -1216,13 +1234,13 @@
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
@@ -1287,7 +1305,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
@@ -1296,7 +1314,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
@@ -1328,7 +1346,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
@@ -1339,7 +1357,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(20, curInterval.value.long_value);
@@ -1373,7 +1391,7 @@
CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval;
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
@@ -1383,14 +1401,14 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(25, curInterval.value.long_value);
EXPECT_EQ(2, curInterval.sampleSize);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ ASSERT_EQ(1UL, valueProducer.mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value -
12.5) < epsilon);
@@ -1421,7 +1439,7 @@
CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
@@ -1430,7 +1448,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(25, curInterval.value.long_value);
@@ -1463,7 +1481,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
@@ -1476,7 +1494,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(5, curInterval.value.long_value);
@@ -1486,7 +1504,7 @@
CreateRepeatedValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 15);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -1497,7 +1515,7 @@
LogEvent event4(/*uid=*/0, /*pid=*/0);
CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -1538,7 +1556,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
@@ -1553,7 +1571,7 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
@@ -1568,7 +1586,7 @@
CreateThreeValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15, 25);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
@@ -1585,7 +1603,7 @@
CreateThreeValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15, 29);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -1599,10 +1617,10 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
+ ASSERT_EQ(1UL, valueProducer.mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+ ASSERT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
+ ASSERT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
@@ -1625,18 +1643,18 @@
metric.set_use_zero_default_base(true);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
- return true;
- }));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
auto iterBase = valueProducer->mCurrentBaseInfo.begin();
@@ -1646,7 +1664,7 @@
EXPECT_EQ(3, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -1654,7 +1672,7 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(11, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
@@ -1682,7 +1700,7 @@
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(4, interval2.value.long_value);
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
auto iterator = valueProducer->mPastBuckets.begin();
EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
EXPECT_EQ(8, iterator->second[0].values[0].long_value);
@@ -1701,18 +1719,18 @@
metric.set_use_zero_default_base(true);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
- return true;
- }));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
const auto& it = valueProducer->mCurrentSlicedBucket.begin();
ValueMetricProducer::Interval& interval1 = it->second[0];
ValueMetricProducer::BaseInfo& baseInfo1 =
@@ -1722,7 +1740,7 @@
EXPECT_EQ(3, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -1730,7 +1748,7 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(11, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
@@ -1751,31 +1769,31 @@
EXPECT_EQ(4, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(4, interval2.value.long_value);
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
// next pull somehow did not happen, skip to end of bucket 3
allData.clear();
allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(5, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
allData.clear();
allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 13));
allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 1, 5));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Get new references now that entries have been deleted from the map
const auto& it3 = valueProducer->mCurrentSlicedBucket.begin();
const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin());
- EXPECT_EQ(it3->second.size(), 1);
- EXPECT_EQ(it4->second.size(), 1);
+ ASSERT_EQ(it3->second.size(), 1);
+ ASSERT_EQ(it4->second.size(), 1);
ValueMetricProducer::Interval& interval3 = it3->second[0];
ValueMetricProducer::Interval& interval4 = it4->second[0];
ValueMetricProducer::BaseInfo& baseInfo3 =
@@ -1794,7 +1812,7 @@
EXPECT_EQ(false, interval4.hasValue);
EXPECT_EQ(8, interval4.value.long_value);
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
}
/*
@@ -1806,18 +1824,18 @@
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
- return true;
- }));
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
auto iterBase = valueProducer->mCurrentBaseInfo.begin();
@@ -1826,7 +1844,7 @@
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -1834,7 +1852,7 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(11, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
@@ -1870,7 +1888,7 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
// Only one interval left. One was trimmed.
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -1909,8 +1927,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
// Used by onConditionChanged.
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
@@ -1922,7 +1940,7 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -1932,7 +1950,7 @@
vector<shared_ptr<LogEvent>> allData;
valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -1942,9 +1960,10 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8); // Condition change to true.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
return true;
@@ -1957,19 +1976,19 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -1979,15 +1998,17 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 50));
- return false;
- }))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 50));
+ return false;
+ }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1); // Condition change to false.
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
return true;
@@ -2001,10 +2022,10 @@
// valueProducer->mCondition = ConditionState::kTrue;
valueProducer->onConditionChanged(true, bucketStartTimeNs);
- EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2019,8 +2040,8 @@
metric.set_max_pull_delay_sec(0);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 120));
@@ -2034,7 +2055,7 @@
// Max delay is set to 0 so pull will exceed max delay.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
- EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
@@ -2060,15 +2081,15 @@
// Event should be skipped since it is from previous bucket.
// Pull should not be called.
valueProducer.onConditionChanged(true, bucketStartTimeNs);
- EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
}
TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
@@ -2083,7 +2104,7 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
valueProducer->mHasGlobalBase = true;
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2100,12 +2121,13 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First onConditionChanged
.WillOnce(Return(false))
// Second onConditionChanged
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
return true;
@@ -2134,9 +2156,9 @@
valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
// Contains base from last pull which was successful.
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2153,14 +2175,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
@@ -2177,9 +2199,9 @@
metric.set_condition(StringToId("SCREEN_ON"));
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 2, _, _))
// First onConditionChanged
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
for (int i = 0; i < 2000; i++) {
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
@@ -2193,8 +2215,8 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
- EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(0UL, valueProducer->mSkippedBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer->mSkippedBuckets.size());
// Bucket 2 start.
vector<shared_ptr<LogEvent>> allData;
@@ -2203,7 +2225,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// First bucket added to mSkippedBuckets after flush.
- EXPECT_EQ(1UL, valueProducer->mSkippedBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mSkippedBuckets.size());
// Check dump report.
ProtoOutputStream output;
@@ -2213,14 +2235,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::DIMENSION_GUARDRAIL_REACHED, dropEvent.drop_reason());
@@ -2234,17 +2256,19 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First onConditionChanged
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
return true;
}))
// Second onConditionChanged
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
return true;
@@ -2271,9 +2295,9 @@
valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
// Contains base from last pull which was successful.
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2290,14 +2314,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
@@ -2312,17 +2336,19 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First onConditionChanged
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
return true;
}))
// Second onConditionChanged
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
return true;
@@ -2349,9 +2375,9 @@
valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
// Last pull failed so base has been reset.
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2367,14 +2393,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
@@ -2384,14 +2410,14 @@
TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
// Start bucket.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
@@ -2401,41 +2427,43 @@
allData.clear();
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
// Bucket 3 empty.
allData.clear();
allData.push_back(CreateNoValuesLogEvent(tagId, bucket3StartTimeNs + 1));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// Data has been trimmed.
- EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
}
TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First onConditionChanged
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
- return true;
- }))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
+ data->clear();
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2445,7 +2473,7 @@
// Empty pull.
valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
@@ -2457,26 +2485,29 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First onConditionChanged
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 2));
- return true;
- }))
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 5));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 11);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 2));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 12);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 5));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
@@ -2484,7 +2515,7 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 11);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 12);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -2496,7 +2527,7 @@
vector<shared_ptr<LogEvent>> allData;
allData.clear();
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// Data is empty, base should be reset.
@@ -2505,7 +2536,7 @@
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1}, {bucketSizeNs - 12 + 1},
{bucketStartTimeNs}, {bucket2StartTimeNs});
}
@@ -2517,20 +2548,20 @@
metric.set_condition(StringToId("SCREEN_ON"));
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _, _))
// First onConditionChanged
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
// End of bucket
vector<shared_ptr<LogEvent>> allData;
@@ -2539,7 +2570,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// Key 1 should be reset since in not present in the most pull.
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
auto iterator = valueProducer->mCurrentSlicedBucket.begin();
auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin();
EXPECT_EQ(true, baseInfoIter->second[0].hasBase);
@@ -2559,18 +2590,20 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
int64_t partialBucketSplitTimeNs = bucketStartTimeNs + bucketSizeNs / 2;
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Initialization.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }))
// notifyAppUpgrade.
- .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
- vector<std::shared_ptr<LogEvent>>* data,
- bool) {
+ .WillOnce(Invoke([partialBucketSplitTimeNs](
+ int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10));
return true;
@@ -2609,17 +2642,19 @@
TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Second onConditionChanged.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 10, 5));
return true;
}))
// Third onConditionChanged.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 10);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 10, 7));
return true;
@@ -2678,14 +2713,14 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
// Initialization.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
@@ -2708,18 +2743,20 @@
int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2;
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Initialization.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }))
// notifyAppUpgrade.
- .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
- vector<std::shared_ptr<LogEvent>>* data,
- bool) {
+ .WillOnce(Invoke([partialBucketSplitTimeNs](
+ int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10));
return true;
@@ -2746,21 +2783,23 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First on condition changed.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }))
// Second on condition changed.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
@@ -2769,7 +2808,7 @@
valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 12);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
@@ -2788,28 +2827,31 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First condition change.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
- return true;
- }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
+ return true;
+ }))
// 2nd condition change.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
- return true;
- }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 8);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
+ return true;
+ }))
// 3rd condition change.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
- return true;
- }));
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
+ return true;
+ }));
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
@@ -2848,9 +2890,9 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
// Initial pull.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
@@ -2869,7 +2911,7 @@
StatsLogReport report = outputStreamToProto(&output);
// Bucket is invalid since we did not pull when dump report was called.
- EXPECT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
}
TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
@@ -2886,9 +2928,9 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
// Initial pull.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
@@ -2912,7 +2954,7 @@
StatsLogReport report = outputStreamToProto(&output);
// Previous bucket is part of the report.
- EXPECT_EQ(1, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().data_size());
EXPECT_EQ(0, report.value_metrics().data(0).bucket_info(0).bucket_num());
}
@@ -2930,16 +2972,18 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Initial pull.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
data->clear();
data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
return true;
}))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
data->clear();
data->push_back(
CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10, tagId, 3, 3));
@@ -2957,8 +3001,8 @@
NO_TIME_CONSTRAINTS, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
- EXPECT_EQ(1, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
}
@@ -2984,17 +3028,19 @@
metric.set_use_diff(false);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
return true;
}))
// condition becomes false
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 20));
return true;
@@ -3006,7 +3052,7 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
// has one slice
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
@@ -3032,9 +3078,9 @@
metric.set_use_diff(false);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
@@ -3083,10 +3129,11 @@
metric.set_use_diff(false);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
return true;
@@ -3122,9 +3169,9 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 20, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 10));
@@ -3145,14 +3192,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
@@ -3167,9 +3214,9 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 50, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
@@ -3198,14 +3245,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(1, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(1, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
@@ -3220,17 +3267,19 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
return true;
}))
// Dump report requested.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 100);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 100, 15));
return true;
@@ -3261,14 +3310,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(1, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(1, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
@@ -3283,17 +3332,19 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
return true;
}))
// Dump report requested.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10000);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 100, 15));
return true;
@@ -3315,14 +3366,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
@@ -3337,10 +3388,11 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
return true;
@@ -3363,14 +3415,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
@@ -3385,17 +3437,19 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
return true;
}))
// Dump report requested.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket4StartTimeNs + 10);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1000, 15));
return true;
@@ -3418,14 +3472,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::MULTIPLE_BUCKETS_SKIPPED, dropEvent.drop_reason());
@@ -3441,17 +3495,19 @@
metric.set_min_bucket_size_nanos(10000000000); // 10 seconds
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
return true;
}))
// Dump report requested.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 9000000);
data->clear();
data->push_back(
CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 9000000, 15));
@@ -3473,14 +3529,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
@@ -3494,9 +3550,9 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _, _))
// Condition change to true.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
@@ -3519,14 +3575,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
@@ -3545,10 +3601,11 @@
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// First condition change event.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
for (int i = 0; i < 2000; i++) {
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
}
@@ -3563,8 +3620,9 @@
.WillOnce(Return(false))
.WillOnce(Return(false))
.WillOnce(Return(false))
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 220);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 220, 10));
return true;
@@ -3602,14 +3660,14 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(0, report.value_metrics().data_size());
- EXPECT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
- EXPECT_EQ(10, report.value_metrics().skipped(0).drop_event_size());
+ ASSERT_EQ(10, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
@@ -3662,38 +3720,43 @@
// Set up ValueMetricProducer.
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE");
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// ValueMetricProducer initialized.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
- return true;
- }))
- // Screen state change to ON.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }))
+ // Screen state change to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5));
return true;
}))
// Screen state change to OFF.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 9));
return true;
}))
// Screen state change to ON.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21));
return true;
}))
// Dump report requested.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30));
return true;
@@ -3710,7 +3773,7 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
// Bucket status after metric initialized.
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -3723,7 +3786,7 @@
auto screenEvent = CreateScreenStateChangedEvent(
bucketStartTimeNs + 5, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -3737,7 +3800,7 @@
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
StateManager::getInstance().onLogEvent(*screenEvent);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -3757,7 +3820,7 @@
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
- EXPECT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -3787,21 +3850,21 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(3, report.value_metrics().data_size());
+ ASSERT_EQ(3, report.value_metrics().data_size());
auto data = report.value_metrics().data(0);
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
data = report.value_metrics().data(1);
- EXPECT_EQ(1, report.value_metrics().data(1).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
EXPECT_EQ(13, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
data = report.value_metrics().data(2);
- EXPECT_EQ(1, report.value_metrics().data(2).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
EXPECT_EQ(12, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
@@ -3818,38 +3881,41 @@
// Set up ValueMetricProducer.
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE_ONOFF");
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// ValueMetricProducer initialized.
- .WillOnce(Invoke(
- [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
- return true;
- }))
- // Screen state change to ON.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }))
+ // Screen state change to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5));
return true;
}))
- // Screen state change to VR.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
- vector<std::shared_ptr<LogEvent>>* data, bool) {
- data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 9));
- return true;
- }))
+ // Screen state change to VR has no pull because it is in the same
+ // state group as ON.
+
+ // Screen state change to ON has no pull because it is in the same
+ // state group as VR.
+
// Screen state change to OFF.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21));
return true;
}))
// Dump report requested.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
data->clear();
data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30));
return true;
@@ -3878,7 +3944,7 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
// Bucket status after metric initialized.
- EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -3891,6 +3957,36 @@
auto screenEvent = CreateScreenStateChangedEvent(
bucketStartTimeNs + 5, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(5, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Bucket status after screen state change ON->VR.
+ // Both ON and VR are in the same state group, so the base should not change.
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
+ android::view::DisplayStateEnum::DISPLAY_STATE_VR);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(5, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Bucket status after screen state change VR->ON.
+ // Both ON and VR are in the same state group, so the base should not change.
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ StateManager::getInstance().onLogEvent(*screenEvent);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
@@ -3901,31 +3997,11 @@
EXPECT_EQ(true, it->second[0].hasValue);
EXPECT_EQ(2, it->second[0].value.long_value);
- // Bucket status after screen state change ON->VR (also ON).
- screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
- android::view::DisplayStateEnum::DISPLAY_STATE_VR);
- StateManager::getInstance().onLogEvent(*screenEvent);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- // Base for dimension key {}
- it = valueProducer->mCurrentSlicedBucket.begin();
- itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_EQ(true, itBase->second[0].hasBase);
- EXPECT_EQ(9, itBase->second[0].base.long_value);
- // Value for dimension, state key {{}, ON GROUP}
- EXPECT_EQ(screenOnGroup.group_id(),
- it->first.getStateValuesKey().getValues()[0].mValue.long_value);
- EXPECT_EQ(true, it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
- // Value for dimension, state key {{}, kStateUnknown}
- it++;
- EXPECT_EQ(true, it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
-
// Bucket status after screen state change VR->OFF.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
StateManager::getInstance().onLogEvent(*screenEvent);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -3949,21 +4025,21 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(3, report.value_metrics().data_size());
+ ASSERT_EQ(3, report.value_metrics().data_size());
auto data = report.value_metrics().data(0);
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
data = report.value_metrics().data(1);
- EXPECT_EQ(1, report.value_metrics().data(1).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
EXPECT_EQ(16, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOnGroup.group_id(), data.slice_by_state(0).group_id());
data = report.value_metrics().data(2);
- EXPECT_EQ(1, report.value_metrics().data(2).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
EXPECT_EQ(9, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
@@ -3990,18 +4066,20 @@
*fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
// ValueMetricProducer initialized.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
data->clear();
data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 2 /*uid*/, 7));
data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1 /*uid*/, 3));
return true;
}))
// Uid 1 process state change from kStateUnknown -> Foreground
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
data->clear();
data->push_back(
CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 1 /*uid*/, 6));
@@ -4012,8 +4090,9 @@
return true;
}))
// Uid 2 process state change from kStateUnknown -> Background
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40);
data->clear();
data->push_back(
CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40, 2 /*uid*/, 9));
@@ -4024,8 +4103,9 @@
return true;
}))
// Uid 1 process state change from Foreground -> Background
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20);
data->clear();
data->push_back(
CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20, 1 /*uid*/, 13));
@@ -4036,8 +4116,9 @@
return true;
}))
// Uid 1 process state change from Background -> Foreground
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40);
data->clear();
data->push_back(
CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40, 1 /*uid*/, 17));
@@ -4048,8 +4129,9 @@
return true;
}))
// Dump report pull.
- .WillOnce(Invoke([](int tagId, const ConfigKey&,
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50);
data->clear();
data->push_back(
CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50, 2 /*uid*/, 20));
@@ -4069,7 +4151,7 @@
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
// Bucket status after metric initialized.
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {uid 1}.
auto it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -4094,7 +4176,7 @@
auto uidProcessEvent = CreateUidProcessStateChangedEvent(
bucketStartTimeNs + 20, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -4121,7 +4203,7 @@
uidProcessEvent = CreateUidProcessStateChangedEvent(
bucketStartTimeNs + 40, 2 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -4151,9 +4233,9 @@
// Buckets flushed after end of first bucket.
// None of the buckets should have a value.
- EXPECT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(4UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(4UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
// Base for dimension key {uid 2}.
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -4161,7 +4243,7 @@
EXPECT_EQ(true, itBase->second[0].hasBase);
EXPECT_EQ(15, itBase->second[0].base.long_value);
// Value for key {uid 2, BACKGROUND}.
- EXPECT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(1006, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_EQ(false, it->second[0].hasValue);
@@ -4172,13 +4254,13 @@
EXPECT_EQ(true, itBase->second[0].hasBase);
EXPECT_EQ(10, itBase->second[0].base.long_value);
// Value for key {uid 1, kStateUnknown}
- EXPECT_EQ(0, it->first.getStateValuesKey().getValues().size());
+ ASSERT_EQ(0, it->first.getStateValuesKey().getValues().size());
// EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_EQ(false, it->second[0].hasValue);
// Value for key {uid 1, FOREGROUND}
it++;
- EXPECT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(1005, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_EQ(false, it->second[0].hasValue);
@@ -4191,9 +4273,9 @@
bucket2StartTimeNs + 20, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- EXPECT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(4UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(4UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
// Base for dimension key {uid 2}.
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -4225,8 +4307,8 @@
bucket2StartTimeNs + 40, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- EXPECT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
// Base for dimension key {uid 2}
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
@@ -4261,10 +4343,10 @@
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
- EXPECT_EQ(5, report.value_metrics().data_size());
+ ASSERT_EQ(5, report.value_metrics().data_size());
auto data = report.value_metrics().data(0);
- EXPECT_EQ(1, data.bucket_info_size());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(4, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
@@ -4272,7 +4354,7 @@
data.slice_by_state(0).value());
data = report.value_metrics().data(1);
- EXPECT_EQ(1, report.value_metrics().data(1).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
data = report.value_metrics().data(2);
@@ -4280,12 +4362,12 @@
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
data.slice_by_state(0).value());
- EXPECT_EQ(2, report.value_metrics().data(2).bucket_info_size());
+ ASSERT_EQ(2, report.value_metrics().data(2).bucket_info_size());
EXPECT_EQ(4, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
EXPECT_EQ(7, report.value_metrics().data(2).bucket_info(1).values(0).value_long());
data = report.value_metrics().data(3);
- EXPECT_EQ(1, report.value_metrics().data(3).bucket_info_size());
+ ASSERT_EQ(1, report.value_metrics().data(3).bucket_info_size());
EXPECT_EQ(3, report.value_metrics().data(3).bucket_info(0).values(0).value_long());
data = report.value_metrics().data(4);
@@ -4293,7 +4375,7 @@
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
data.slice_by_state(0).value());
- EXPECT_EQ(2, report.value_metrics().data(4).bucket_info_size());
+ ASSERT_EQ(2, report.value_metrics().data(4).bucket_info_size());
EXPECT_EQ(6, report.value_metrics().data(4).bucket_info(0).values(0).value_long());
EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
}
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 46ef0f6..eeb38a4 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -38,10 +38,11 @@
int64_t nextPulltimeNs, int64_t intervalNs));
MOCK_METHOD3(UnRegisterReceiver,
void(int tagId, const ConfigKey& key, wp<PullDataReceiver> receiver));
- MOCK_METHOD4(Pull, bool(const int pullCode, const ConfigKey& key,
+ MOCK_METHOD5(Pull, bool(const int pullCode, const ConfigKey& key, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data, bool useUids));
- MOCK_METHOD4(Pull, bool(const int pullCode, const vector<int32_t>& uids,
- vector<std::shared_ptr<LogEvent>>* data, bool useUids));
+ MOCK_METHOD5(Pull,
+ bool(const int pullCode, const vector<int32_t>& uids, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool useUids));
MOCK_METHOD2(RegisterPullUidProvider,
void(const ConfigKey& configKey, wp<PullUidProvider> provider));
MOCK_METHOD2(UnregisterPullUidProvider,
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index 7b952d7..e384b6a 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -86,28 +86,34 @@
// wait for the data to be written.
std::this_thread::sleep_for(100ms);
- int expected_data_size = expectedData.ByteSize();
+ // Because we might receive heartbeats from statsd, consisting of data sizes
+ // of 0, encapsulate reads within a while loop.
+ bool readAtom = false;
+ while (!readAtom) {
+ // Read the atom size.
+ size_t dataSize = 0;
+ read(fds_data[0], &dataSize, sizeof(dataSize));
+ if (dataSize == 0) continue;
+ EXPECT_EQ(expectedData.ByteSize(), int(dataSize));
- // now read from the pipe. firstly read the atom size.
- size_t dataSize = 0;
- EXPECT_EQ((int)sizeof(dataSize), read(fds_data[0], &dataSize, sizeof(dataSize)));
+ // Read that much data in proto binary format.
+ vector<uint8_t> dataBuffer(dataSize);
+ EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize));
- EXPECT_EQ(expected_data_size, (int)dataSize);
+ // Make sure the received bytes can be parsed to an atom.
+ ShellData receivedAtom;
+ EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
- // then read that much data which is the atom in proto binary format
- vector<uint8_t> dataBuffer(dataSize);
- EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize));
+ // Serialize the expected atom to byte array and compare to make sure
+ // they are the same.
+ vector<uint8_t> expectedAtomBuffer(expectedData.ByteSize());
+ expectedData.SerializeToArray(expectedAtomBuffer.data(), expectedData.ByteSize());
+ EXPECT_EQ(expectedAtomBuffer, dataBuffer);
- // make sure the received bytes can be parsed to an atom
- ShellData receivedAtom;
- EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
+ readAtom = true;
+ }
- // serialze the expected atom to bytes. and compare. to make sure they are the same.
- vector<uint8_t> atomBuffer(expected_data_size);
- expectedData.SerializeToArray(&atomBuffer[0], expected_data_size);
- EXPECT_EQ(atomBuffer, dataBuffer);
close(fds_data[0]);
-
if (reader.joinable()) {
reader.join();
}
@@ -184,8 +190,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
const vector<int32_t> uids = {AID_SYSTEM};
- EXPECT_CALL(*pullerManager, Pull(10016, uids, _, _))
- .WillRepeatedly(Invoke([](int tagId, const vector<int32_t>&,
+ EXPECT_CALL(*pullerManager, Pull(10016, uids, _, _, _))
+ .WillRepeatedly(Invoke([](int tagId, const vector<int32_t>&, const int64_t,
vector<std::shared_ptr<LogEvent>>* data, bool) {
data->clear();
data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid1, /*timeMillis=*/kCpuTime1));
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index ba2a4cf..530ac5e 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -50,8 +50,9 @@
std::vector<Update> updates;
void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
- const HashableDimensionKey& primaryKey, int oldState, int newState) {
- updates.emplace_back(primaryKey, newState);
+ const HashableDimensionKey& primaryKey, const FieldValue& oldState,
+ const FieldValue& newState) {
+ updates.emplace_back(primaryKey, newState.mValue.int_value);
}
};
@@ -205,7 +206,7 @@
std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent(timestampNs, attributionUids1,
attributionTags1, "wakelockName");
mgr.onLogEvent(*event1);
- EXPECT_EQ(1, listener->updates.size());
+ ASSERT_EQ(1, listener->updates.size());
EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(1, listener->updates[0].mState);
listener->updates.clear();
@@ -213,17 +214,17 @@
std::unique_ptr<LogEvent> event2 = CreateAcquireWakelockEvent(
timestampNs + 1000, attributionUids1, attributionTags1, "wakelockName");
mgr.onLogEvent(*event2);
- EXPECT_EQ(0, listener->updates.size());
+ ASSERT_EQ(0, listener->updates.size());
std::unique_ptr<LogEvent> event3 = CreateReleaseWakelockEvent(
timestampNs + 2000, attributionUids1, attributionTags1, "wakelockName");
mgr.onLogEvent(*event3);
- EXPECT_EQ(0, listener->updates.size());
+ ASSERT_EQ(0, listener->updates.size());
std::unique_ptr<LogEvent> event4 = CreateReleaseWakelockEvent(
timestampNs + 3000, attributionUids1, attributionTags1, "wakelockName");
mgr.onLogEvent(*event4);
- EXPECT_EQ(1, listener->updates.size());
+ ASSERT_EQ(1, listener->updates.size());
EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(0, listener->updates[0].mState);
}
@@ -247,7 +248,7 @@
CreateBleScanStateChangedEvent(timestampNs, attributionUids1, attributionTags1,
BleScanStateChanged::ON, false, false, false);
mgr.onLogEvent(*event1);
- EXPECT_EQ(1, listener->updates.size());
+ ASSERT_EQ(1, listener->updates.size());
EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
FieldValue stateFieldValue;
@@ -259,7 +260,7 @@
CreateBleScanStateChangedEvent(timestampNs + 1000, attributionUids2, attributionTags1,
BleScanStateChanged::ON, false, false, false);
mgr.onLogEvent(*event2);
- EXPECT_EQ(1, listener->updates.size());
+ ASSERT_EQ(1, listener->updates.size());
EXPECT_EQ(2000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, listener->updates[0].mKey, &stateFieldValue);
@@ -270,7 +271,7 @@
CreateBleScanStateChangedEvent(timestampNs + 2000, attributionUids2, attributionTags1,
BleScanStateChanged::RESET, false, false, false);
mgr.onLogEvent(*event3);
- EXPECT_EQ(2, listener->updates.size());
+ ASSERT_EQ(2, listener->updates.size());
for (const TestStateListener::Update& update : listener->updates) {
EXPECT_EQ(BleScanStateChanged::OFF, update.mState);
@@ -294,7 +295,7 @@
mgr.onLogEvent(*event);
// check listener was updated
- EXPECT_EQ(1, listener1->updates.size());
+ ASSERT_EQ(1, listener1->updates.size());
EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
EXPECT_EQ(2, listener1->updates[0].mState);
@@ -319,7 +320,7 @@
mgr.onLogEvent(*event);
// check listener was updated
- EXPECT_EQ(1, listener1->updates.size());
+ ASSERT_EQ(1, listener1->updates.size());
EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(1002, listener1->updates[0].mState);
@@ -346,8 +347,8 @@
EXPECT_EQ(1, mgr.getListenersCount(util::WAKELOCK_STATE_CHANGED));
// Check listener was updated.
- EXPECT_EQ(1, listener1->updates.size());
- EXPECT_EQ(3, listener1->updates[0].mKey.getValues().size());
+ ASSERT_EQ(1, listener1->updates.size());
+ ASSERT_EQ(3, listener1->updates[0].mKey.getValues().size());
EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value);
EXPECT_EQ("wakelockName", listener1->updates[0].mKey.getValues()[2].mValue.str_value);
@@ -388,7 +389,7 @@
mgr.onLogEvent(*event);
// check listener was updated
- EXPECT_EQ(1, listener1->updates.size());
+ ASSERT_EQ(1, listener1->updates.size());
EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(1, listener1->updates[0].mState);
@@ -416,9 +417,9 @@
// check listener was updated
mgr.onLogEvent(*event1);
- EXPECT_EQ(0, listener1->updates.size());
+ ASSERT_EQ(0, listener1->updates.size());
mgr.onLogEvent(*event2);
- EXPECT_EQ(0, listener1->updates.size());
+ ASSERT_EQ(0, listener1->updates.size());
}
TEST(StateTrackerTest, TestStateQuery) {
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 2315fd7..6a7ad1f 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -956,11 +956,11 @@
void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId,
const int uid, const string& tag) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_EQ(value.value_tuple().dimensions_value_size(), 2);
+ ASSERT_EQ(value.value_tuple().dimensions_value_size(), 2);
// Attribution field.
EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
// Uid field.
- EXPECT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value_size(), 1);
+ ASSERT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).value_int(),
uid);
@@ -971,7 +971,7 @@
void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1);
+ ASSERT_EQ(value.value_tuple().dimensions_value_size(), 1);
// Attribution field.
EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
// Uid only.
@@ -985,7 +985,7 @@
void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx);
+ ASSERT_GT(value.value_tuple().dimensions_value_size(), node_idx);
// Attribution field.
EXPECT_EQ(value.value_tuple().dimensions_value(node_idx).field(), 1);
EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
@@ -997,7 +997,7 @@
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx);
+ ASSERT_GT(value.value_tuple().dimensions_value_size(), node_idx);
// Attribution field.
EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx).field());
// Uid only.
@@ -1016,7 +1016,7 @@
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int atomId, int uid, const std::string& tag) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_EQ(1, value.value_tuple().dimensions_value_size());
+ ASSERT_EQ(1, value.value_tuple().dimensions_value_size());
// Attribution field.
EXPECT_EQ(1, value.value_tuple().dimensions_value(0).field());
// Uid only.
@@ -1339,7 +1339,7 @@
// stats_event.h/c uses a vector as opposed to a buffer.
p.buffer.assign(buffer, buffer + size);
parcels.push_back(std::move(p));
- AStatsEvent_write(event);
+ AStatsEvent_release(event);
}
resultReceiver->pullFinished(atomTag, /*success=*/true, parcels);
return Status::ok();
diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp
index 27a86e42..74eafbf 100644
--- a/cmds/statsd/tests/storage/StorageManager_test.cpp
+++ b/cmds/statsd/tests/storage/StorageManager_test.cpp
@@ -49,10 +49,10 @@
EXPECT_TRUE(result);
EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
- EXPECT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
+ ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
EXPECT_EQ(trainInfo.status, trainInfoResult.status);
- EXPECT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
+ ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
}
@@ -75,10 +75,10 @@
EXPECT_TRUE(result);
EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
- EXPECT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
+ ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
EXPECT_EQ(trainInfo.status, trainInfoResult.status);
- EXPECT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
+ ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
}
diff --git a/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java b/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java
index c35f7fc..3b14be7 100644
--- a/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java
+++ b/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java
@@ -16,6 +16,7 @@
package com.android.commands.uiautomator;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.UiAutomation;
import android.graphics.Point;
import android.hardware.display.DisplayManagerGlobal;
@@ -61,11 +62,14 @@
public void run(String[] args) {
File dumpFile = DEFAULT_DUMP_FILE;
boolean verboseMode = true;
+ boolean allWindows = false;
for (String arg : args) {
if (arg.equals("--compressed"))
verboseMode = false;
- else if (!arg.startsWith("-")) {
+ else if (arg.equals("--windows")) {
+ allWindows = true;
+ } else if (!arg.startsWith("-")) {
dumpFile = new File(arg);
}
}
@@ -85,18 +89,28 @@
try {
UiAutomation uiAutomation = automationWrapper.getUiAutomation();
uiAutomation.waitForIdle(1000, 1000 * 10);
- AccessibilityNodeInfo info = uiAutomation.getRootInActiveWindow();
- if (info == null) {
- System.err.println("ERROR: null root node returned by UiTestAutomationBridge.");
- return;
- }
+ if (allWindows) {
+ AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
+ info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+ uiAutomation.setServiceInfo(info);
+ AccessibilityNodeInfoDumper.dumpWindowsToFile(
+ uiAutomation.getWindowsOnAllDisplays(), dumpFile,
+ DisplayManagerGlobal.getInstance());
+ } else {
+ AccessibilityNodeInfo info = uiAutomation.getRootInActiveWindow();
+ if (info == null) {
+ System.err.println("ERROR: null root node returned by UiTestAutomationBridge.");
+ return;
+ }
- Display display =
- DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
- int rotation = display.getRotation();
- Point size = new Point();
- display.getSize(size);
- AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x, size.y);
+ Display display =
+ DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+ int rotation = display.getRotation();
+ Point size = new Point();
+ display.getSize(size);
+ AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x,
+ size.y);
+ }
} catch (TimeoutException re) {
System.err.println("ERROR: could not get idle state.");
return;
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index 63c51e8..ab198b3 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -16,11 +16,17 @@
package com.android.uiautomator.core;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.Environment;
import android.os.SystemClock;
import android.util.Log;
+import android.util.SparseArray;
import android.util.Xml;
+import android.view.Display;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
import org.xmlpull.v1.XmlSerializer;
@@ -28,6 +34,7 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
+import java.util.List;
/**
*
@@ -98,6 +105,95 @@
Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms");
}
+ /**
+ * Using {@link AccessibilityWindowInfo} this method will dump some window information and
+ * then walk the layout hierarchy of it's
+ * and generates an xml dump to the location specified by <code>dumpFile</code>
+ * @param allWindows All windows indexed by display-id.
+ * @param dumpFile The file to dump to.
+ */
+ public static void dumpWindowsToFile(SparseArray<List<AccessibilityWindowInfo>> allWindows,
+ File dumpFile, DisplayManagerGlobal displayManager) {
+ if (allWindows.size() == 0) {
+ return;
+ }
+ final long startTime = SystemClock.uptimeMillis();
+ try {
+ FileWriter writer = new FileWriter(dumpFile);
+ XmlSerializer serializer = Xml.newSerializer();
+ StringWriter stringWriter = new StringWriter();
+ serializer.setOutput(stringWriter);
+ serializer.startDocument("UTF-8", true);
+ serializer.startTag("", "displays");
+ for (int d = 0, nd = allWindows.size(); d < nd; ++d) {
+ int displayId = allWindows.keyAt(d);
+ Display display = displayManager.getRealDisplay(displayId);
+ if (display == null) {
+ continue;
+ }
+ final List<AccessibilityWindowInfo> windows = allWindows.valueAt(d);
+ if (windows.isEmpty()) {
+ continue;
+ }
+ serializer.startTag("", "display");
+ serializer.attribute("", "id", Integer.toString(displayId));
+ int rotation = display.getRotation();
+ Point size = new Point();
+ display.getSize(size);
+ for (int i = 0, n = windows.size(); i < n; ++i) {
+ dumpWindowRec(windows.get(i), serializer, i, size.x, size.y, rotation);
+ }
+ serializer.endTag("", "display");
+ }
+ serializer.endTag("", "displays");
+ serializer.endDocument();
+ writer.write(stringWriter.toString());
+ writer.close();
+ } catch (IOException e) {
+ Log.e(LOGTAG, "failed to dump window to file", e);
+ }
+ final long endTime = SystemClock.uptimeMillis();
+ Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms");
+ }
+
+ private static void dumpWindowRec(AccessibilityWindowInfo winfo, XmlSerializer serializer,
+ int index, int width, int height, int rotation) throws IOException {
+ serializer.startTag("", "window");
+ serializer.attribute("", "index", Integer.toString(index));
+ final CharSequence title = winfo.getTitle();
+ serializer.attribute("", "title", title != null ? title.toString() : "");
+ final Rect tmpBounds = new Rect();
+ winfo.getBoundsInScreen(tmpBounds);
+ serializer.attribute("", "bounds", tmpBounds.toShortString());
+ serializer.attribute("", "active", Boolean.toString(winfo.isActive()));
+ serializer.attribute("", "focused", Boolean.toString(winfo.isFocused()));
+ serializer.attribute("", "accessibility-focused",
+ Boolean.toString(winfo.isAccessibilityFocused()));
+ serializer.attribute("", "id", Integer.toString(winfo.getId()));
+ serializer.attribute("", "layer", Integer.toString(winfo.getLayer()));
+ serializer.attribute("", "type", AccessibilityWindowInfo.typeToString(winfo.getType()));
+ int count = winfo.getChildCount();
+ for (int i = 0; i < count; ++i) {
+ AccessibilityWindowInfo child = winfo.getChild(i);
+ if (child == null) {
+ Log.i(LOGTAG, String.format("Null window child %d/%d, parent: %s", i, count,
+ winfo.getTitle()));
+ continue;
+ }
+ dumpWindowRec(child, serializer, i, width, height, rotation);
+ child.recycle();
+ }
+ AccessibilityNodeInfo root = winfo.getRoot();
+ if (root != null) {
+ serializer.startTag("", "hierarchy");
+ serializer.attribute("", "rotation", Integer.toString(rotation));
+ dumpNodeRec(root, serializer, 0, width, height);
+ root.recycle();
+ serializer.endTag("", "hierarchy");
+ }
+ serializer.endTag("", "window");
+ }
+
private static void dumpNodeRec(AccessibilityNodeInfo node, XmlSerializer serializer,int index,
int width, int height) throws IOException {
serializer.startTag("", "node");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bfae632..af5fafb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,8 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.os.Process.myUid;
import static java.lang.Character.MIN_VALUE;
@@ -947,9 +949,8 @@
/** @hide */
boolean mEnterAnimationComplete;
- /** Track last dispatched multi-window and PiP mode to client, internal debug purpose **/
- private Boolean mLastDispatchedIsInMultiWindowMode;
- private Boolean mLastDispatchedIsInPictureInPictureMode;
+ private boolean mIsInMultiWindowMode;
+ private boolean mIsInPictureInPictureMode;
private final WindowControllerCallback mWindowControllerCallback =
new WindowControllerCallback() {
@@ -2748,7 +2749,7 @@
* @return True if the activity is in multi-window mode.
*/
public boolean isInMultiWindowMode() {
- return mLastDispatchedIsInMultiWindowMode == Boolean.TRUE;
+ return mIsInMultiWindowMode;
}
/**
@@ -2791,7 +2792,7 @@
* @return True if the activity is in picture-in-picture mode.
*/
public boolean isInPictureInPictureMode() {
- return mLastDispatchedIsInPictureInPictureMode == Boolean.TRUE;
+ return mIsInPictureInPictureMode;
}
/**
@@ -7142,14 +7143,19 @@
writer.print(mResumed); writer.print(" mStopped=");
writer.print(mStopped); writer.print(" mFinished=");
writer.println(mFinished);
- writer.print(innerPrefix); writer.print("mLastDispatchedIsInMultiWindowMode=");
- writer.print(mLastDispatchedIsInMultiWindowMode);
- writer.print(" mLastDispatchedIsInPictureInPictureMode=");
- writer.println(mLastDispatchedIsInPictureInPictureMode);
+ writer.print(innerPrefix); writer.print("mIsInMultiWindowMode=");
+ writer.print(mIsInMultiWindowMode);
+ writer.print(" mIsInPictureInPictureMode=");
+ writer.println(mIsInPictureInPictureMode);
writer.print(innerPrefix); writer.print("mChangingConfigurations=");
writer.println(mChangingConfigurations);
writer.print(innerPrefix); writer.print("mCurrentConfig=");
writer.println(mCurrentConfig);
+ if (getResources().hasOverrideDisplayAdjustments()) {
+ writer.print(innerPrefix);
+ writer.print("FixedRotationAdjustments=");
+ writer.println(getResources().getDisplayAdjustments().getFixedRotationAdjustments());
+ }
mFragments.dumpLoaders(innerPrefix, fd, writer, args);
mFragments.getFragmentManager().dump(innerPrefix, fd, writer, args);
@@ -7977,6 +7983,11 @@
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
dispatchActivityPreCreated(icicle);
mCanEnterPictureInPicture = true;
+ // initialize mIsInMultiWindowMode and mIsInPictureInPictureMode before onCreate
+ final int windowingMode = getResources().getConfiguration().windowConfiguration
+ .getWindowingMode();
+ mIsInMultiWindowMode = inMultiWindowMode(windowingMode);
+ mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED;
restoreHasCurrentPermissionRequest(icicle);
if (persistentState != null) {
onCreate(icicle, persistentState);
@@ -8245,7 +8256,7 @@
if (mWindow != null) {
mWindow.onMultiWindowModeChanged();
}
- mLastDispatchedIsInMultiWindowMode = isInMultiWindowMode;
+ mIsInMultiWindowMode = isInMultiWindowMode;
onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
}
@@ -8258,7 +8269,7 @@
if (mWindow != null) {
mWindow.onPictureInPictureModeChanged(isInPictureInPictureMode);
}
- mLastDispatchedIsInPictureInPictureMode = isInPictureInPictureMode;
+ mIsInPictureInPictureMode = isInPictureInPictureMode;
onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9067069..97b704c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -601,6 +601,20 @@
@TestApi
public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
+ // TODO: remove this when development is done.
+ // These are debug flags used between OomAdjuster and AppOpsService to detect and report absence
+ // of the real flags.
+ /** @hide */
+ public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q = 1 << 27;
+ /** @hide */
+ public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q = 1 << 28;
+ /** @hide */
+ public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29;
+ /** @hide */
+ public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30;
+ /** @hide */
+ public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
+
/** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
@TestApi
public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
@@ -623,6 +637,51 @@
public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = PROCESS_CAPABILITY_FOREGROUND_CAMERA
| PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ /**
+ * Print capability bits in human-readable form.
+ * @hide
+ */
+ public static void printCapabilitiesSummary(PrintWriter pw, @ProcessCapability int caps) {
+ pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-');
+ pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-');
+ pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-');
+ }
+
+ /**
+ * Print capability bits in human-readable form.
+ * @hide
+ */
+ public static void printCapabilitiesFull(PrintWriter pw, @ProcessCapability int caps) {
+ printCapabilitiesSummary(pw, caps);
+ if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
+ pw.print(" !L");
+ }
+ if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
+ pw.print(" !C");
+ }
+ if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) {
+ pw.print(" !Cq");
+ }
+ if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
+ pw.print(" !M");
+ }
+ if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) {
+ pw.print(" !Mq");
+ }
+ final int remain = caps & ~(PROCESS_CAPABILITY_FOREGROUND_LOCATION
+ | PROCESS_CAPABILITY_FOREGROUND_CAMERA
+ | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
+ | DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION
+ | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA
+ | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q
+ | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
+ | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q);
+ if (remain != 0) {
+ pw.print('+');
+ pw.print(remain);
+ }
+ }
+
// NOTE: If PROCESS_STATEs are added, then new fields must be added
// to frameworks/base/core/proto/android/app/enums.proto and the following method must
// be updated to correctly map between them.
@@ -2231,7 +2290,8 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mId);
ComponentName.writeToParcel(mTopActivityComponent, dest);
- dest.writeParcelable(mSnapshot, 0);
+ dest.writeParcelable(mSnapshot != null && !mSnapshot.isDestroyed() ? mSnapshot : null,
+ 0);
dest.writeInt(mColorSpace.getId());
dest.writeInt(mOrientation);
dest.writeInt(mRotation);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e97ebd7..8e43ca3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -156,6 +156,8 @@
import android.view.Choreographer;
import android.view.ContextThemeWrapper;
import android.view.Display;
+import android.view.DisplayAdjustments;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewDebug;
@@ -215,6 +217,7 @@
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
final class RemoteServiceException extends AndroidRuntimeException {
public RemoteServiceException(String msg) {
@@ -405,6 +408,9 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final ResourcesManager mResourcesManager;
+ /** The active adjustments that override the {@link DisplayAdjustments} in resources. */
+ private ArrayList<Pair<IBinder, Consumer<DisplayAdjustments>>> mActiveRotationAdjustments;
+
// Registry of remote cancellation transports pending a reply with reply handles.
@GuardedBy("this")
private @Nullable Map<SafeCancellationTransport, CancellationSignal> mRemoteCancellations;
@@ -541,6 +547,12 @@
@UnsupportedAppUsage
boolean mPreserveWindow;
+ /**
+ * If non-null, the activity is launching with a specified rotation, the adjustments should
+ * be consumed before activity creation.
+ */
+ FixedRotationAdjustments mPendingFixedRotationAdjustments;
+
@LifecycleState
private int mLifecycleState = PRE_ON_CREATE;
@@ -557,7 +569,7 @@
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean isForward,
ProfilerInfo profilerInfo, ClientTransactionHandler client,
- IBinder assistToken) {
+ IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
this.token = token;
this.assistToken = assistToken;
this.ident = ident;
@@ -575,6 +587,7 @@
this.overrideConfig = overrideConfig;
this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
compatInfo);
+ mPendingFixedRotationAdjustments = fixedRotationAdjustments;
init();
}
@@ -1525,6 +1538,12 @@
IoUtils.closeQuietly(pfd);
}
+ @Override
+ public void dumpCacheInfo(ParcelFileDescriptor pfd, String[] args) {
+ PropertyInvalidatedCache.dumpCacheInfo(pfd.getFileDescriptor(), args);
+ IoUtils.closeQuietly(pfd);
+ }
+
private File getDatabasesDir(Context context) {
// There's no simple way to get the databases/ path, so do it this way.
return context.getDatabasePath("a").getParentFile();
@@ -3233,6 +3252,44 @@
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
+ @Override
+ public void handleFixedRotationAdjustments(@NonNull IBinder token,
+ @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
+ final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
+ ? displayAdjustments -> displayAdjustments.setFixedRotationAdjustments(
+ fixedRotationAdjustments)
+ : null;
+ if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
+ // No resources are associated with the token.
+ return;
+ }
+ if (mActivities.get(token) == null) {
+ // Only apply the override to application for activity token because the appearance of
+ // activity is usually more sensitive to the application resources.
+ return;
+ }
+
+ // Apply the last override to application resources for compatibility. Because the Resources
+ // of Display can be from application, e.g.
+ // applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
+ // and the deprecated usage:
+ // applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
+ final Consumer<DisplayAdjustments> appOverride;
+ if (mActiveRotationAdjustments == null) {
+ mActiveRotationAdjustments = new ArrayList<>(2);
+ }
+ if (override != null) {
+ mActiveRotationAdjustments.add(Pair.create(token, override));
+ appOverride = override;
+ } else {
+ mActiveRotationAdjustments.removeIf(adjustmentsPair -> adjustmentsPair.first == token);
+ appOverride = mActiveRotationAdjustments.isEmpty()
+ ? null
+ : mActiveRotationAdjustments.get(mActiveRotationAdjustments.size() - 1).second;
+ }
+ mInitialApplication.getResources().overrideDisplayAdjustments(appOverride);
+ }
+
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
@@ -3446,6 +3503,13 @@
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
+ // The rotation adjustments must be applied before creating the activity, so the activity
+ // can get the adjusted display info during creation.
+ if (r.mPendingFixedRotationAdjustments != null) {
+ handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments);
+ r.mPendingFixedRotationAdjustments = null;
+ }
+
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show
@@ -5844,6 +5908,12 @@
}
}
+ /**
+ * Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling
+ * this method prevents any calls to
+ * {@link #handleActivityConfigurationChanged(IBinder, Configuration, int, boolean)} from
+ * processing any configurations older than {@code overrideConfig}.
+ */
@Override
public void updatePendingActivityConfiguration(IBinder activityToken,
Configuration overrideConfig) {
@@ -5860,13 +5930,22 @@
}
synchronized (r) {
+ if (r.mPendingOverrideConfig != null
+ && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Activity has newer configuration pending so drop this"
+ + " transaction. overrideConfig=" + overrideConfig
+ + " r.mPendingOverrideConfig=" + r.mPendingOverrideConfig);
+ }
+ return;
+ }
r.mPendingOverrideConfig = overrideConfig;
}
}
@Override
public void handleActivityConfigurationChanged(IBinder activityToken,
- Configuration overrideConfig, int displayId) {
+ @NonNull Configuration overrideConfig, int displayId) {
handleActivityConfigurationChanged(activityToken, overrideConfig, displayId,
// This is the only place that uses alwaysReportChange=true. The entry point should
// be from ActivityConfigurationChangeItem or MoveToDisplayItem, so the server side
@@ -5877,15 +5956,18 @@
}
/**
- * Handle new activity configuration and/or move to a different display.
+ * Handle new activity configuration and/or move to a different display. This method is a noop
+ * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with
+ * a newer config than {@code overrideConfig}.
+ *
* @param activityToken Target activity token.
* @param overrideConfig Activity override config.
* @param displayId Id of the display where activity was moved to, -1 if there was no move and
* value didn't change.
* @param alwaysReportChange If the configuration is changed, always report to activity.
*/
- void handleActivityConfigurationChanged(IBinder activityToken, Configuration overrideConfig,
- int displayId, boolean alwaysReportChange) {
+ void handleActivityConfigurationChanged(IBinder activityToken,
+ @NonNull Configuration overrideConfig, int displayId, boolean alwaysReportChange) {
ActivityClientRecord r = mActivities.get(activityToken);
// Check input params.
if (r == null || r.activity == null) {
@@ -5896,9 +5978,13 @@
&& displayId != r.activity.getDisplayId();
synchronized (r) {
- if (r.mPendingOverrideConfig != null
- && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
- overrideConfig = r.mPendingOverrideConfig;
+ if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) {
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Activity has newer configuration pending so drop this"
+ + " transaction. overrideConfig=" + overrideConfig
+ + " r.mPendingOverrideConfig=" + r.mPendingOverrideConfig);
+ }
+ return;
}
r.mPendingOverrideConfig = null;
}
@@ -6144,6 +6230,12 @@
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
+ if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+ for (PropertyInvalidatedCache pic : PropertyInvalidatedCache.getActiveCaches()) {
+ pic.clear();
+ }
+ }
+
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
final int N = callbacks.size();
@@ -6420,7 +6512,7 @@
// Allow binder tracing, and application-generated systrace messages if we're profileable.
boolean isAppProfileable = data.appInfo.isProfileableByShell();
Trace.setAppTracingAllowed(isAppProfileable);
- if (isAppProfileable && data.enableBinderTracking) {
+ if ((isAppProfileable || Build.IS_DEBUGGABLE) && data.enableBinderTracking) {
Binder.enableTracing();
}
@@ -7455,7 +7547,15 @@
try {
super.rename(oldPath, newPath);
} catch (ErrnoException e) {
- if (e.errno == OsConstants.EXDEV && oldPath.startsWith("/storage/")) {
+ // On emulated volumes, we have bind mounts for /Android/data and
+ // /Android/obb, which prevents move from working across those directories
+ // and other directories on the filesystem. To work around that, try to
+ // recover by doing a copy instead.
+ // Note that we only do this for "/storage/emulated", because public volumes
+ // don't have these bind mounts, neither do private volumes that are not
+ // the primary storage.
+ if (e.errno == OsConstants.EXDEV && oldPath.startsWith("/storage/emulated")
+ && newPath.startsWith("/storage/emulated")) {
Log.v(TAG, "Recovering failed rename " + oldPath + " to " + newPath);
try {
Files.move(new File(oldPath).toPath(), new File(newPath).toPath(),
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d321288..b058dcd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3688,7 +3688,7 @@
/**
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+ @UnsupportedAppUsage(/*maxTargetSdk = Build.VERSION_CODES.R,*/ publicAlternatives = "{@code "
+ "#getOpStr()}")
public int getOp() {
return mOp;
@@ -3707,7 +3707,7 @@
* @deprecated Use {@link #getLastAccessTime(int)} instead
*/
@Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+ @UnsupportedAppUsage(/*maxTargetSdk = Build.VERSION_CODES.R,*/ publicAlternatives = "{@code "
+ "#getLastAccessTime(int)}")
public long getTime() {
return getLastAccessTime(OP_FLAGS_ALL);
@@ -3822,7 +3822,7 @@
* @deprecated Use {@link #getLastRejectTime(int)} instead
*/
@Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+ @UnsupportedAppUsage(/*maxTargetSdk = Build.VERSION_CODES.R,*/ publicAlternatives = "{@code "
+ "#getLastRejectTime(int)}")
public long getRejectTime() {
return getLastRejectTime(OP_FLAGS_ALL);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f883b60..6bd8fd7 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1574,7 +1574,7 @@
}
Drawable badge = new LauncherIcons(mContext).getBadgeDrawable(
getUserManager().getUserIconBadgeResId(user.getIdentifier()),
- getUserBadgeColor(user));
+ getUserBadgeColor(user, false));
return getBadgedDrawable(icon, badge, null, true);
}
@@ -1588,8 +1588,16 @@
return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
}
- /** Returns the color of the user's actual badge (not the badge's shadow). */
- private int getUserBadgeColor(UserHandle user) {
+ /**
+ * Returns the color of the user's actual badge (not the badge's shadow).
+ * @param checkTheme whether to check the theme to determine the badge color. This should be
+ * true if the background is determined by the theme. Otherwise, if
+ * checkTheme is false, returns the color assuming a light background.
+ */
+ private int getUserBadgeColor(UserHandle user, boolean checkTheme) {
+ if (checkTheme && mContext.getResources().getConfiguration().isNightModeActive()) {
+ return getUserManager().getUserBadgeDarkColor(user.getIdentifier());
+ }
return getUserManager().getUserBadgeColor(user.getIdentifier());
}
@@ -1603,11 +1611,14 @@
}
Drawable badgeForeground = getDrawableForDensity(
getUserManager().getUserBadgeResId(user.getIdentifier()), density);
- badgeForeground.setTint(getUserBadgeColor(user));
+ badgeForeground.setTint(getUserBadgeColor(user, false));
Drawable badge = new LayerDrawable(new Drawable[] {badgeColor, badgeForeground });
return badge;
}
+ /**
+ * Returns the badge color based on whether device has dark theme enabled or not.
+ */
@Override
public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
if (!hasUserBadge(user.getIdentifier())) {
@@ -1616,7 +1627,7 @@
Drawable badge = getDrawableForDensity(
getUserManager().getUserBadgeNoBackgroundResId(user.getIdentifier()), density);
if (badge != null) {
- badge.setTint(getUserBadgeColor(user));
+ badge.setTint(getUserBadgeColor(user, true));
}
return badge;
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 83465b0..2df756e 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -25,6 +25,7 @@
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.MergedConfiguration;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
@@ -167,6 +168,10 @@
/** Deliver app configuration change notification. */
public abstract void handleConfigurationChanged(Configuration config);
+ /** Apply addition adjustments to override display information. */
+ public abstract void handleFixedRotationAdjustments(IBinder token,
+ FixedRotationAdjustments fixedRotationAdjustments);
+
/**
* Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
* provided token.
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index fe13b8f..f236813 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -58,7 +58,7 @@
@RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
public void startDream(@NonNull ComponentName name) {
try {
- mService.testDream(mContext.getUserId(), name);
+ mService.dream();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -99,4 +99,22 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns whether the device is Dreaming.
+ *
+ * <p> This is only used for testing the dream service APIs.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE)
+ public boolean isDreaming() {
+ try {
+ return mService.isDreaming();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 833bfed..e84c5e5 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -99,7 +99,6 @@
void unregisterUidObserver(in IUidObserver observer);
boolean isUidActive(int uid, String callingPackage);
int getUidProcessState(int uid, in String callingPackage);
- boolean isUidActiveOrForeground(int uid, String callingPackage);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
@@ -673,4 +672,9 @@
* @param state The customized state data
*/
void setProcessStateSummary(in byte[] state);
+
+ /**
+ * Return whether the app freezer is supported (true) or not (false) by this system.
+ */
+ boolean isAppFreezerSupported();
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 3ce7689..be1681b 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -229,7 +229,16 @@
void unregisterTaskStackListener(in ITaskStackListener listener);
void setTaskResizeable(int taskId, int resizeableMode);
void toggleFreeformWindowingMode(in IBinder token);
- void resizeTask(int taskId, in Rect bounds, int resizeMode);
+
+ /**
+ * Resize the task with given bounds
+ *
+ * @param taskId The id of the task to set the bounds for.
+ * @param bounds The new bounds.
+ * @param resizeMode Resize mode defined as {@code ActivityTaskManager#RESIZE_MODE_*} constants.
+ * @return Return true on success. Otherwise false.
+ */
+ boolean resizeTask(int taskId, in Rect bounds, int resizeMode);
void moveStackToDisplay(int stackId, int displayId);
void removeStack(int stackId);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 1f6e4ca..6e9157e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -119,6 +119,7 @@
boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable,
in String[] args);
void dumpGfxInfo(in ParcelFileDescriptor fd, in String[] args);
+ void dumpCacheInfo(in ParcelFileDescriptor fd, in String[] args);
void dumpProvider(in ParcelFileDescriptor fd, IBinder servicetoken,
in String[] args);
void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 8dfce14..4c3e888 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -58,7 +58,9 @@
void setShowBadge(String pkg, int uid, boolean showBadge);
boolean canShowBadge(String pkg, int uid);
- boolean hasSentMessage(String pkg, int uid);
+ boolean isInInvalidMsgState(String pkg, int uid);
+ boolean hasUserDemotedInvalidMsgApp(String pkg, int uid);
+ void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted);
void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled);
/**
* Updates the notification's enabled state. Additionally locks importance for all of the
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 3110e18..01cf2b94a 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -26,12 +26,20 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastPrintWriter;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
+import java.util.Set;
+import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;
/**
@@ -197,6 +205,14 @@
@GuardedBy("sCorkLock")
private static final HashMap<String, Integer> sCorks = new HashMap<>();
+ /**
+ * Weakly references all cache objects in the current process, allowing us to iterate over
+ * them all for purposes like issuing debug dumps and reacting to memory pressure.
+ */
+ @GuardedBy("sCorkLock")
+ private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches =
+ new WeakHashMap<>();
+
private final Object mLock = new Object();
/**
@@ -225,6 +241,11 @@
private boolean mDisabled = false;
/**
+ * Maximum number of entries the cache will maintain.
+ */
+ private final int mMaxEntries;
+
+ /**
* Make a new property invalidated cache.
*
* @param maxEntries Maximum number of entries to cache; LRU discard
@@ -232,6 +253,7 @@
*/
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
mPropertyName = propertyName;
+ mMaxEntries = maxEntries;
mCache = new LinkedHashMap<Query, Result>(
2 /* start small */,
0.75f /* default load factor */,
@@ -241,6 +263,9 @@
return size() > maxEntries;
}
};
+ synchronized (sCorkLock) {
+ sCaches.put(this, null);
+ }
}
/**
@@ -248,6 +273,9 @@
*/
public final void clear() {
synchronized (mLock) {
+ if (DEBUG) {
+ Log.d(TAG, "clearing cache for " + mPropertyName);
+ }
mCache.clear();
}
}
@@ -710,4 +738,87 @@
Log.d(TAG, "disabling all caches in the process");
sEnabled = false;
}
+
+ /**
+ * Returns a list of caches alive at the current time.
+ */
+ public static ArrayList<PropertyInvalidatedCache> getActiveCaches() {
+ synchronized (sCorkLock) {
+ return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
+ }
+ }
+
+ /**
+ * Returns a list of the active corks in a process.
+ */
+ public static ArrayList<Map.Entry<String, Integer>> getActiveCorks() {
+ synchronized (sCorkLock) {
+ return new ArrayList<Map.Entry<String, Integer>>(sCorks.entrySet());
+ }
+ }
+
+ private void dumpContents(PrintWriter pw, String[] args) {
+ synchronized (mLock) {
+ pw.println(String.format(" Cache Property Name: %s", cacheName()));
+ pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce));
+ pw.println(String.format(" Current Size: %d, Max Size: %d",
+ mCache.entrySet().size(), mMaxEntries));
+ pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true"));
+
+ Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet();
+ if (cacheEntries.size() == 0) {
+ pw.println("");
+ return;
+ }
+
+ pw.println("");
+ pw.println(" Contents:");
+ for (Map.Entry<Query, Result> entry : cacheEntries) {
+ String key = Objects.toString(entry.getKey());
+ String value = Objects.toString(entry.getValue());
+
+ pw.println(String.format(" Key: %s\n Value: %s\n", key, value));
+ }
+ }
+ }
+
+ /**
+ * Dumps contents of every cache in the process to the provided FileDescriptor.
+ */
+ public static void dumpCacheInfo(FileDescriptor fd, String[] args) {
+ ArrayList<PropertyInvalidatedCache> activeCaches;
+ ArrayList<Map.Entry<String, Integer>> activeCorks;
+
+ try (
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new FastPrintWriter(fout);
+ ) {
+ if (!sEnabled) {
+ pw.println(" Caching is disabled in this process.");
+ return;
+ }
+
+ synchronized (sCorkLock) {
+ activeCaches = getActiveCaches();
+ activeCorks = getActiveCorks();
+
+ if (activeCorks.size() > 0) {
+ pw.println(" Corking Status:");
+ for (int i = 0; i < activeCorks.size(); i++) {
+ Map.Entry<String, Integer> entry = activeCorks.get(i);
+ pw.println(String.format(" Property Name: %s Count: %d",
+ entry.getKey(), entry.getValue()));
+ }
+ }
+ }
+
+ for (int i = 0; i < activeCaches.size(); i++) {
+ PropertyInvalidatedCache currentCache = activeCaches.get(i);
+ currentCache.dumpContents(pw, args);
+ pw.flush();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to dump PropertyInvalidatedCache instances");
+ }
+ }
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 106f8ac..1aae04d 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -59,6 +59,7 @@
import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/** @hide */
@@ -1296,6 +1297,35 @@
}
}
+ /**
+ * Overrides the display adjustments of all resources which are associated with the given token.
+ *
+ * @param token The token that owns the resources.
+ * @param override The operation to override the existing display adjustments. If it is null,
+ * the override adjustments will be cleared.
+ * @return {@code true} if the override takes effect.
+ */
+ public boolean overrideTokenDisplayAdjustments(IBinder token,
+ @Nullable Consumer<DisplayAdjustments> override) {
+ boolean handled = false;
+ synchronized (this) {
+ final ActivityResources tokenResources = mActivityResourceReferences.get(token);
+ if (tokenResources == null) {
+ return false;
+ }
+ final ArrayList<WeakReference<Resources>> resourcesRefs =
+ tokenResources.activityResources;
+ for (int i = resourcesRefs.size() - 1; i >= 0; i--) {
+ final Resources res = resourcesRefs.get(i).get();
+ if (res != null) {
+ res.overrideDisplayAdjustments(override);
+ handled = true;
+ }
+ }
+ }
+ return handled;
+ }
+
private class UpdateHandler implements Resources.UpdateCallbacks {
/**
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index 0d4e16b..8b52242 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -19,6 +19,7 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
+import android.annotation.NonNull;
import android.app.ClientTransactionHandler;
import android.content.res.Configuration;
import android.os.IBinder;
@@ -37,6 +38,8 @@
@Override
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+ // Notify the client of an upcoming change in the token configuration. This ensures that
+ // batches of config change items only process the newest configuration.
client.updatePendingActivityConfiguration(token, mConfiguration);
}
@@ -55,7 +58,11 @@
private ActivityConfigurationChangeItem() {}
/** Obtain an instance initialized with provided params. */
- public static ActivityConfigurationChangeItem obtain(Configuration config) {
+ public static ActivityConfigurationChangeItem obtain(@NonNull Configuration config) {
+ if (config == null) {
+ throw new IllegalArgumentException("Config must not be null.");
+ }
+
ActivityConfigurationChangeItem instance =
ObjectPool.obtain(ActivityConfigurationChangeItem.class);
if (instance == null) {
@@ -68,7 +75,7 @@
@Override
public void recycle() {
- mConfiguration = null;
+ mConfiguration = Configuration.EMPTY;
ObjectPool.recycle(this);
}
diff --git a/core/java/android/app/servertransaction/FixedRotationAdjustmentsItem.java b/core/java/android/app/servertransaction/FixedRotationAdjustmentsItem.java
new file mode 100644
index 0000000..6183d5f
--- /dev/null
+++ b/core/java/android/app/servertransaction/FixedRotationAdjustmentsItem.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
+
+import java.util.Objects;
+
+/**
+ * The request to update display adjustments for a rotated activity or window token.
+ * @hide
+ */
+public class FixedRotationAdjustmentsItem extends ClientTransactionItem {
+
+ /** The token who may have {@link android.content.res.Resources}. */
+ private IBinder mToken;
+
+ /**
+ * The adjustments for the display adjustments of resources. If it is null, the existing
+ * rotation adjustments will be dropped to restore natural state.
+ */
+ private FixedRotationAdjustments mFixedRotationAdjustments;
+
+ private FixedRotationAdjustmentsItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static FixedRotationAdjustmentsItem obtain(IBinder token,
+ FixedRotationAdjustments fixedRotationAdjustments) {
+ FixedRotationAdjustmentsItem instance =
+ ObjectPool.obtain(FixedRotationAdjustmentsItem.class);
+ if (instance == null) {
+ instance = new FixedRotationAdjustmentsItem();
+ }
+ instance.mToken = token;
+ instance.mFixedRotationAdjustments = fixedRotationAdjustments;
+
+ return instance;
+ }
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ client.handleFixedRotationAdjustments(mToken, mFixedRotationAdjustments);
+ }
+
+ @Override
+ public void recycle() {
+ mToken = null;
+ mFixedRotationAdjustments = null;
+ ObjectPool.recycle(this);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mToken);
+ dest.writeTypedObject(mFixedRotationAdjustments, flags);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final FixedRotationAdjustmentsItem other = (FixedRotationAdjustmentsItem) o;
+ return Objects.equals(mToken, other.mToken)
+ && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(mToken);
+ result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
+ return result;
+ }
+
+ private FixedRotationAdjustmentsItem(Parcel in) {
+ mToken = in.readStrongBinder();
+ mFixedRotationAdjustments = in.readTypedObject(FixedRotationAdjustments.CREATOR);
+ }
+
+ public static final Creator<FixedRotationAdjustmentsItem> CREATOR =
+ new Creator<FixedRotationAdjustmentsItem>() {
+ public FixedRotationAdjustmentsItem createFromParcel(Parcel in) {
+ return new FixedRotationAdjustmentsItem(in);
+ }
+
+ public FixedRotationAdjustmentsItem[] newArray(int size) {
+ return new FixedRotationAdjustmentsItem[size];
+ }
+ };
+}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 9ab6e7f..2e7b626 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -33,6 +33,7 @@
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.Trace;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -64,6 +65,7 @@
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
private IBinder mAssistToken;
+ private FixedRotationAdjustments mFixedRotationAdjustments;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
@@ -79,7 +81,7 @@
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
- mProfilerInfo, client, mAssistToken);
+ mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -101,14 +103,14 @@
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo,
- IBinder assistToken) {
+ IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
}
setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
voiceInteractor, procState, state, persistentState, pendingResults,
- pendingNewIntents, isForward, profilerInfo, assistToken);
+ pendingNewIntents, isForward, profilerInfo, assistToken, fixedRotationAdjustments);
return instance;
}
@@ -116,7 +118,7 @@
@Override
public void recycle() {
setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
- false, null, null);
+ false, null, null, null);
ObjectPool.recycle(this);
}
@@ -142,6 +144,7 @@
dest.writeBoolean(mIsForward);
dest.writeTypedObject(mProfilerInfo, flags);
dest.writeStrongBinder(mAssistToken);
+ dest.writeTypedObject(mFixedRotationAdjustments, flags);
}
/** Read from Parcel. */
@@ -156,7 +159,8 @@
in.createTypedArrayList(ResultInfo.CREATOR),
in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(),
in.readTypedObject(ProfilerInfo.CREATOR),
- in.readStrongBinder());
+ in.readStrongBinder(),
+ in.readTypedObject(FixedRotationAdjustments.CREATOR));
}
public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR =
@@ -192,7 +196,8 @@
&& Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
&& mIsForward == other.mIsForward
&& Objects.equals(mProfilerInfo, other.mProfilerInfo)
- && Objects.equals(mAssistToken, other.mAssistToken);
+ && Objects.equals(mAssistToken, other.mAssistToken)
+ && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
}
@Override
@@ -212,6 +217,7 @@
result = 31 * result + (mIsForward ? 1 : 0);
result = 31 * result + Objects.hashCode(mProfilerInfo);
result = 31 * result + Objects.hashCode(mAssistToken);
+ result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
return result;
}
@@ -247,7 +253,7 @@
+ ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
+ ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
+ ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo
- + " assistToken=" + mAssistToken
+ + ",assistToken=" + mAssistToken + ",rotationAdj=" + mFixedRotationAdjustments
+ "}";
}
@@ -257,7 +263,8 @@
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
- boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken) {
+ boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
+ FixedRotationAdjustments fixedRotationAdjustments) {
instance.mIntent = intent;
instance.mIdent = ident;
instance.mInfo = info;
@@ -274,5 +281,6 @@
instance.mIsForward = isForward;
instance.mProfilerInfo = profilerInfo;
instance.mAssistToken = assistToken;
+ instance.mFixedRotationAdjustments = fixedRotationAdjustments;
}
}
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index f6d3dbd..9a457a3 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -18,6 +18,7 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
import android.app.ClientTransactionHandler;
import android.content.res.Configuration;
import android.os.IBinder;
@@ -36,6 +37,13 @@
private Configuration mConfiguration;
@Override
+ public void preExecute(ClientTransactionHandler client, IBinder token) {
+ // Notify the client of an upcoming change in the token configuration. This ensures that
+ // batches of config change items only process the newest configuration.
+ client.updatePendingActivityConfiguration(token, mConfiguration);
+ }
+
+ @Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
@@ -49,7 +57,12 @@
private MoveToDisplayItem() {}
/** Obtain an instance initialized with provided params. */
- public static MoveToDisplayItem obtain(int targetDisplayId, Configuration configuration) {
+ public static MoveToDisplayItem obtain(int targetDisplayId,
+ @NonNull Configuration configuration) {
+ if (configuration == null) {
+ throw new IllegalArgumentException("Configuration must not be null");
+ }
+
MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class);
if (instance == null) {
instance = new MoveToDisplayItem();
@@ -63,7 +76,7 @@
@Override
public void recycle() {
mTargetDisplayId = 0;
- mConfiguration = null;
+ mConfiguration = Configuration.EMPTY;
ObjectPool.recycle(this);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a4627d..c409613 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1449,7 +1449,7 @@
* on these schemes.
*
* @param uri The desired URI.
- * @return InputStream
+ * @return InputStream or {@code null} if the provider recently crashed.
* @throws FileNotFoundException if the provided URI could not be opened.
* @see #openAssetFileDescriptor(Uri, String)
*/
@@ -1484,6 +1484,9 @@
/**
* Synonym for {@link #openOutputStream(Uri, String)
* openOutputStream(uri, "w")}.
+ *
+ * @param uri The desired URI.
+ * @return an OutputStream or {@code null} if the provider recently crashed.
* @throws FileNotFoundException if the provided URI could not be opened.
*/
public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
@@ -1506,7 +1509,7 @@
*
* @param uri The desired URI.
* @param mode May be "w", "wa", "rw", or "rwt".
- * @return OutputStream
+ * @return an OutputStream or {@code null} if the provider recently crashed.
* @throws FileNotFoundException if the provided URI could not be opened.
* @see #openAssetFileDescriptor(Uri, String)
*/
@@ -1563,8 +1566,9 @@
* @param uri The desired URI to open.
* @param mode The file mode to use, as per {@link ContentProvider#openFile
* ContentProvider.openFile}.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException if no
* file exists under the URI or the mode is invalid.
* @see #openAssetFileDescriptor(Uri, String)
@@ -1608,8 +1612,9 @@
* @param cancellationSignal A signal to cancel the operation in progress,
* or null if none. If the operation is canceled, then
* {@link OperationCanceledException} will be thrown.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException if no
* file exists under the URI or the mode is invalid.
* @see #openAssetFileDescriptor(Uri, String)
@@ -1698,8 +1703,9 @@
* @param uri The desired URI to open.
* @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
* ContentProvider.openAssetFile}.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
*/
@@ -1754,8 +1760,9 @@
* @param cancellationSignal A signal to cancel the operation in progress, or null if
* none. If the operation is canceled, then
* {@link OperationCanceledException} will be thrown.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
*/
@@ -1902,9 +1909,9 @@
* it is returning.
* @param opts Additional provider-dependent options.
* @return Returns a new ParcelFileDescriptor from which you can read the
- * data stream from the provider. Note that this may be a pipe, meaning
- * you can't seek in it. The only seek you should do is if the
- * AssetFileDescriptor contains an offset, to move to that offset before
+ * data stream from the provider or {@code null} if the provider recently crashed.
+ * Note that this may be a pipe, meaning you can't seek in it. The only seek you
+ * should do is if the AssetFileDescriptor contains an offset, to move to that offset before
* reading. You own this descriptor and are responsible for closing it when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* data of the desired type exists under the URI.
@@ -1938,9 +1945,9 @@
* or null if none. If the operation is canceled, then
* {@link OperationCanceledException} will be thrown.
* @return Returns a new ParcelFileDescriptor from which you can read the
- * data stream from the provider. Note that this may be a pipe, meaning
- * you can't seek in it. The only seek you should do is if the
- * AssetFileDescriptor contains an offset, to move to that offset before
+ * data stream from the provider or {@code null} if the provider recently crashed.
+ * Note that this may be a pipe, meaning you can't seek in it. The only seek you
+ * should do is if the AssetFileDescriptor contains an offset, to move to that offset before
* reading. You own this descriptor and are responsible for closing it when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* data of the desired type exists under the URI.
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 745add1..79da1f6 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1183,7 +1183,8 @@
return NO_MATCH_DATA;
}
}
- if (mPort >= 0) {
+ // if we're dealing with wildcard support, we ignore ports
+ if (!wildcardSupported && mPort >= 0) {
if (mPort != data.getPort()) {
return NO_MATCH_DATA;
}
@@ -1580,12 +1581,13 @@
* @param wildcardSupported if true, will allow parameters to use wildcards
*/
private int matchData(String type, String scheme, Uri data, boolean wildcardSupported) {
- final ArrayList<String> types = mDataTypes;
+ final boolean wildcardWithMimegroups = wildcardSupported && countMimeGroups() != 0;
+ final List<String> types = mDataTypes;
final ArrayList<String> schemes = mDataSchemes;
int match = MATCH_CATEGORY_EMPTY;
- if (types == null && schemes == null) {
+ if (!wildcardWithMimegroups && types == null && schemes == null) {
return ((type == null && data == null)
? (MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL) : NO_MATCH_DATA);
}
@@ -1640,7 +1642,9 @@
}
}
- if (types != null) {
+ if (wildcardWithMimegroups) {
+ return MATCH_CATEGORY_TYPE;
+ } else if (types != null) {
if (findMimeType(type)) {
match = MATCH_CATEGORY_TYPE;
} else {
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 37baae3..0105896 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -51,6 +51,9 @@
void uninstall(in VersionedPackage versionedPackage, String callerPackageName, int flags,
in IntentSender statusReceiver, int userId);
+ void uninstallExistingPackage(in VersionedPackage versionedPackage, String callerPackageName,
+ in IntentSender statusReceiver, int userId);
+
void installExistingPackage(String packageName, int installFlags, int installReason,
in IntentSender statusReceiver, int userId, in List<String> whiteListedPermissions);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 8bebaff..f257326 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -235,6 +235,16 @@
void deletePackageVersioned(in VersionedPackage versionedPackage,
IPackageDeleteObserver2 observer, int userId, int flags);
+ /**
+ * Delete a package for a specific user.
+ *
+ * @param versionedPackage The package to delete.
+ * @param observer a callback to use to notify when the package deletion in finished.
+ * @param userId the id of the user for whom to delete the package
+ */
+ void deleteExistingPackageAsUser(in VersionedPackage versionedPackage,
+ IPackageDeleteObserver2 observer, int userId);
+
@UnsupportedAppUsage
String getInstallerPackageName(in String packageName);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index bbcac56..4299e80 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1870,7 +1870,7 @@
* an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
* respectively to the default launcher app.
*
- * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
+ * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.</h3>
*
* <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
* {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
@@ -1887,7 +1887,7 @@
*
* <p>See also {@link ShortcutManager} for more details.
*
- * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
+ * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.</h3>
*
* <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
* an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 85a3986..ed75504 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -720,6 +720,27 @@
}
}
+ /**
+ * Uninstall the given package for the user for which this installer was created if the package
+ * will still exist for other users on the device.
+ *
+ * @param packageName The package to install.
+ * @param statusReceiver Where to deliver the result.
+ *
+ * {@hide}
+ */
+ @RequiresPermission(Manifest.permission.DELETE_PACKAGES)
+ public void uninstallExistingPackage(@NonNull String packageName,
+ @Nullable IntentSender statusReceiver) {
+ Objects.requireNonNull(packageName, "packageName cannot be null");
+ try {
+ mInstaller.uninstallExistingPackage(
+ new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+ mInstallerPackageName, statusReceiver, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/** {@hide} */
@SystemApi
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d06a69c..2f488cd 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -47,8 +47,13 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.ArtManager;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
@@ -380,6 +385,9 @@
* <p>
* Note: this flag may cause less information about currently installed
* applications to be returned.
+ * <p>
+ * Note: use of this flag requires the android.permission.QUERY_ALL_PACKAGES
+ * permission to see uninstalled packages.
*/
public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
@@ -3046,6 +3054,16 @@
public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports a system interface for the user to select
+ * and bind device control services provided by applications.
+ *
+ * @see android.service.controls.ControlsProviderService
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_CONTROLS = "android.software.controls";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
* the requisite hardware support to support reboot escrow of synthetic password for updates.
*
@@ -6037,28 +6055,25 @@
@Nullable
public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
@PackageInfoFlags int flags) {
- final PackageParser parser = new PackageParser();
- parser.setCallback(new PackageParser.CallbackImpl(this));
- final File apkFile = new File(archiveFilePath);
- try {
- if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
- // Caller expressed an explicit opinion about what encryption
- // aware/unaware components they want to see, so fall through and
- // give them what they want
- } else {
- // Caller expressed no opinion, so match everything
- flags |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
- }
+ if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
+ // Caller expressed no opinion about what encryption
+ // aware/unaware components they want to see, so match both
+ flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ }
- PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
- if ((flags & GET_SIGNATURES) != 0) {
- PackageParser.collectCertificates(pkg, false /* skipVerify */);
- }
- PackageUserState state = new PackageUserState();
- return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
- } catch (PackageParserException e) {
+ boolean collectCertificates = (flags & PackageManager.GET_SIGNATURES) != 0
+ || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0;
+
+ ParseInput input = ParseTypeImpl.forParsingWithoutPlatformCompat().reset();
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefault(input,
+ new File(archiveFilePath), 0, collectCertificates);
+ if (result.isError()) {
return null;
}
+ return PackageInfoWithoutStateUtils.generate(result.getResult(), null, flags, 0, 0, null,
+ new PackageUserState(), UserHandle.getCallingUserId());
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3b3521f..312e98e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1517,6 +1517,10 @@
? null : "must have at least one '.' separator";
}
+ /**
+ * @deprecated Use {@link android.content.pm.parsing.ApkLiteParseUtils#parsePackageSplitNames}
+ */
+ @Deprecated
public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
AttributeSet attrs) throws IOException, XmlPullParserException,
PackageParserException {
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 2f416a2..d2172d3 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -16,6 +16,8 @@
package android.content.pm.parsing;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.compat.annotation.UnsupportedAppUsage;
@@ -23,6 +25,8 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.VerifierInfo;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.ApkAssets;
import android.content.res.XmlResourceParser;
import android.os.Trace;
@@ -70,82 +74,93 @@
*
* @see PackageParser#parsePackage(File, int)
*/
- @UnsupportedAppUsage
- public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parsePackageLite(ParseInput input,
+ File packageFile, int flags) {
if (packageFile.isDirectory()) {
- return parseClusterPackageLite(packageFile, flags);
+ return parseClusterPackageLite(input, packageFile, flags);
} else {
- return parseMonolithicPackageLite(packageFile, flags);
+ return parseMonolithicPackageLite(input, packageFile, flags);
}
}
- public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parseMonolithicPackageLite(
+ ParseInput input, File packageFile, int flags) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
- final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags);
- final String packagePath = packageFile.getAbsolutePath();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
- null, null);
+ try {
+ ParseResult<PackageParser.ApkLite> result = parseApkLite(input, packageFile, flags);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ final PackageParser.ApkLite baseApk = result.getResult();
+ final String packagePath = packageFile.getAbsolutePath();
+ return input.success(
+ new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
+ null, null));
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
- public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parseClusterPackageLite(ParseInput input,
+ File packageDir, int flags) {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split");
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ "No packages found in split");
}
// Apk directory is directly nested under the current directory
if (files.length == 1 && files[0].isDirectory()) {
- return parseClusterPackageLite(files[0], flags);
+ return parseClusterPackageLite(input, files[0], flags);
}
String packageName = null;
int versionCode = 0;
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>();
- for (File file : files) {
- if (PackageParser.isApkFile(file)) {
- final PackageParser.ApkLite lite = parseApkLite(file, flags);
-
- // Assert that all package names and version codes are
- // consistent with the first one we encounter.
- if (packageName == null) {
- packageName = lite.packageName;
- versionCode = lite.versionCode;
- } else {
- if (!packageName.equals(lite.packageName)) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent package " + lite.packageName + " in " + file
- + "; expected " + packageName);
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+ try {
+ for (File file : files) {
+ if (PackageParser.isApkFile(file)) {
+ ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags);
+ if (result.isError()) {
+ return input.error(result);
}
- if (versionCode != lite.versionCode) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent version " + lite.versionCode + " in " + file
- + "; expected " + versionCode);
- }
- }
- // Assert that each split is defined only oncuses-static-libe
- if (apks.put(lite.splitName, lite) != null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Split name " + lite.splitName
- + " defined more than once; most recent was " + file);
+ final PackageParser.ApkLite lite = result.getResult();
+ // Assert that all package names and version codes are
+ // consistent with the first one we encounter.
+ if (packageName == null) {
+ packageName = lite.packageName;
+ versionCode = lite.versionCode;
+ } else {
+ if (!packageName.equals(lite.packageName)) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent package " + lite.packageName + " in " + file
+ + "; expected " + packageName);
+ }
+ if (versionCode != lite.versionCode) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent version " + lite.versionCode + " in " + file
+ + "; expected " + versionCode);
+ }
+ }
+
+ // Assert that each split is defined only oncuses-static-libe
+ if (apks.put(lite.splitName, lite) != null) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Split name " + lite.splitName
+ + " defined more than once; most recent was " + file);
+ }
}
}
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final PackageParser.ApkLite baseApk = apks.remove(null);
if (baseApk == null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Missing base APK in " + packageDir);
}
@@ -180,8 +195,9 @@
}
final String codePath = packageDir.getAbsolutePath();
- return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits,
- usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
+ return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames,
+ isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
+ splitRevisionCodes));
}
/**
@@ -192,9 +208,9 @@
* @param flags optional parse flags, such as
* {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
*/
- public static PackageParser.ApkLite parseApkLite(File apkFile, int flags)
- throws PackageParser.PackageParserException {
- return parseApkLiteInner(apkFile, null, null, flags);
+ public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, File apkFile,
+ int flags) {
+ return parseApkLiteInner(input, apkFile, null, null, flags);
}
/**
@@ -206,13 +222,13 @@
* @param flags optional parse flags, such as
* {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
*/
- public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName,
- int flags) throws PackageParser.PackageParserException {
- return parseApkLiteInner(null, fd, debugPathName, flags);
+ public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input,
+ FileDescriptor fd, String debugPathName, int flags) {
+ return parseApkLiteInner(input, null, fd, debugPathName, flags);
}
- private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd,
- String debugPathName, int flags) throws PackageParser.PackageParserException {
+ private static ParseResult<PackageParser.ApkLite> parseApkLiteInner(ParseInput input,
+ File apkFile, FileDescriptor fd, String debugPathName, int flags) {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
XmlResourceParser parser = null;
@@ -223,8 +239,7 @@
? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */, null /* assets */)
: ApkAssets.loadFromPath(apkPath);
} catch (IOException e) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse " + apkPath, e);
}
@@ -235,9 +250,15 @@
final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(),
- skipVerify, false, PackageParser.SigningDetails.UNKNOWN,
- DEFAULT_TARGET_SDK_VERSION);
+ ParseResult<PackageParser.SigningDetails> result =
+ ParsingPackageUtils.getSigningDetails(input,
+ apkFile.getAbsolutePath(), skipVerify, false,
+ PackageParser.SigningDetails.UNKNOWN,
+ DEFAULT_TARGET_SDK_VERSION);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ signingDetails = result.getResult();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -246,12 +267,10 @@
}
final AttributeSet attrs = parser;
- return parseApkLite(apkPath, parser, attrs, signingDetails);
-
+ return parseApkLite(input, apkPath, parser, attrs, signingDetails);
} catch (XmlPullParserException | IOException | RuntimeException e) {
Slog.w(TAG, "Failed to parse " + apkPath, e);
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
@@ -265,12 +284,16 @@
}
}
- private static PackageParser.ApkLite parseApkLite(
+ private static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input,
String codePath, XmlPullParser parser, AttributeSet attrs,
PackageParser.SigningDetails signingDetails)
- throws IOException, XmlPullParserException, PackageParser.PackageParserException {
- final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(
- parser, attrs);
+ throws IOException, XmlPullParserException {
+ ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser, attrs);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ Pair<String, String> packageSplit = result.getResult();
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
@@ -394,8 +417,7 @@
usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
if (usesSplitName == null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"<uses-split> tag requires 'android:name' attribute");
}
} else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) {
@@ -423,12 +445,54 @@
overlayPriority = 0;
}
- return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
- isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
- versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
- coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
- isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion,
- targetSdkVersion);
+ return input.success(new PackageParser.ApkLite(codePath, packageSplit.first,
+ packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired,
+ versionCode, versionCodeMajor, revisionCode, installLocation, verifiers,
+ signingDetails, coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex,
+ extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority,
+ minSdkVersion, targetSdkVersion));
+ }
+
+ public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
+ XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No start tag found");
+ }
+ if (!parser.getName().equals(PackageParser.TAG_MANIFEST)) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No <manifest> tag");
+ }
+
+ final String packageName = attrs.getAttributeValue(null, "package");
+ if (!"android".equals(packageName)) {
+ final String error = PackageParser.validateName(packageName, true, true);
+ if (error != null) {
+ return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest package: " + error);
+ }
+ }
+
+ String splitName = attrs.getAttributeValue(null, "split");
+ if (splitName != null) {
+ if (splitName.length() == 0) {
+ splitName = null;
+ } else {
+ final String error = PackageParser.validateName(splitName, false, false);
+ if (error != null) {
+ return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest split: " + error);
+ }
+ }
+ }
+
+ return input.success(Pair.create(packageName.intern(),
+ (splitName != null) ? splitName.intern() : splitName));
}
public static VerifierInfo parseVerifier(AttributeSet attrs) {
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index d3d15c8..5a79475 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -29,6 +29,7 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.annotation.AnyRes;
+import android.annotation.CheckResult;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -130,28 +131,46 @@
public static final String TAG = ParsingUtils.TAG;
/**
+ * @see #parseDefault(ParseInput, File, int, boolean)
+ */
+ @NonNull
+ public static ParseResult<ParsingPackage> parseDefaultOneTime(File file,
+ @PackageParser.ParseFlags int parseFlags, boolean collectCertificates) {
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+ return parseDefault(input, file, parseFlags, collectCertificates);
+ }
+
+ /**
* For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
* request, without caching the input object and without querying the internal system state
* for feature support.
*/
@NonNull
- public static ParseResult<ParsingPackage> parseDefaultOneTime(File file, int flags,
- @NonNull ParseInput.Callback inputCallback, @NonNull Callback callback) {
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
- // Caller expressed no opinion about what encryption
- // aware/unaware components they want to see, so match both
- flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
- }
-
- ParseInput input = new ParseTypeImpl(inputCallback).reset();
+ public static ParseResult<ParsingPackage> parseDefault(ParseInput input, File file,
+ @PackageParser.ParseFlags int parseFlags, boolean collectCertificates) {
ParseResult<ParsingPackage> result;
+ ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, new Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission parsing
+ // and will force <uses-permission/> declarations to include all requiredNotFeature
+ // permissions and exclude all requiredFeature permissions. This mirrors the old
+ // behavior.
+ return false;
+ }
- ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, callback);
+ @Override
+ public ParsingPackage startParsingPackage(
+ @NonNull String packageName,
+ @NonNull String baseCodePath,
+ @NonNull String codePath,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
+ return new ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray);
+ }
+ });
try {
- result = parser.parsePackage(input, file, flags);
+ result = parser.parsePackage(input, file, parseFlags);
if (result.isError()) {
return result;
}
@@ -162,9 +181,9 @@
try {
ParsingPackage pkg = result.getResult();
- if ((flags & PackageManager.GET_SIGNATURES) != 0
- || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
- ParsingPackageUtils.collectCertificates(pkg, false /* skipVerify */);
+ if (collectCertificates) {
+ pkg.setSigningDetails(
+ ParsingPackageUtils.getSigningDetails(pkg, false /* skipVerify */));
}
return input.success(pkg);
@@ -197,7 +216,7 @@
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
@@ -223,12 +242,17 @@
* split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
- int flags) throws PackageParserException {
- final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
- 0);
+ int flags) {
+ ParseResult<PackageParser.PackageLite> liteResult =
+ ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
+ if (liteResult.isError()) {
+ return input.error(liteResult);
+ }
+
+ final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + packageDir);
@@ -275,6 +299,9 @@
pkg.setUse32BitAbi(lite.use32bitAbi);
return input.success(pkg);
+ } catch (PackageParserException e) {
+ return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to load assets: " + lite.baseCodePath, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -284,12 +311,17 @@
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
- final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
- flags);
+ ParseResult<PackageParser.PackageLite> liteResult =
+ ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
+ if (liteResult.isError()) {
+ return input.error(liteResult);
+ }
+
+ final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + apkFile);
@@ -373,8 +405,13 @@
}
}
- pkg.setVolumeUuid(volumeUuid)
- .setSigningDetails(SigningDetails.UNKNOWN);
+ pkg.setVolumeUuid(volumeUuid);
+
+ if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
+ pkg.setSigningDetails(getSigningDetails(pkg, false));
+ } else {
+ pkg.setSigningDetails(SigningDetails.UNKNOWN);
+ }
return input.success(pkg);
} catch (Exception e) {
@@ -426,24 +463,25 @@
*/
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
- throws XmlPullParserException, IOException {
+ throws XmlPullParserException, IOException, PackageParserException {
final String splitName;
final String pkgName;
- try {
- Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
- parser);
- pkgName = packageSplit.first;
- splitName = packageSplit.second;
+ ParseResult<Pair<String, String>> packageSplitResult =
+ ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
+ if (packageSplitResult.isError()) {
+ return input.error(packageSplitResult);
+ }
- if (!TextUtils.isEmpty(splitName)) {
- return input.error(
- PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Expected base APK, but found split " + splitName
- );
- }
- } catch (PackageParserException e) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+ Pair<String, String> packageSplit = packageSplitResult.getResult();
+ pkgName = packageSplit.first;
+ splitName = packageSplit.second;
+
+ if (!TextUtils.isEmpty(splitName)) {
+ return input.error(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Expected base APK, but found split " + splitName
+ );
}
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
@@ -2624,31 +2662,53 @@
/**
* Collect certificates from all the APKs described in the given package. Also asserts that
* all APK contents are signed correctly and consistently.
+ *
+ * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse
+ * call if requested. Leaving this as an optional method for the caller means we have to
+ * construct a dummy ParseInput.
*/
- public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
+ @CheckResult
+ public static SigningDetails getSigningDetails(ParsingPackageRead pkg, boolean skipVerify)
throws PackageParserException {
SigningDetails signingDetails = SigningDetails.UNKNOWN;
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- signingDetails = collectCertificates(
+ ParseResult<SigningDetails> result = getSigningDetails(
+ input,
pkg.getBaseCodePath(),
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
+ if (result.isError()) {
+ throw new PackageParser.PackageParserException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
+ }
+
+ signingDetails = result.getResult();
String[] splitCodePaths = pkg.getSplitCodePaths();
if (!ArrayUtils.isEmpty(splitCodePaths)) {
for (int i = 0; i < splitCodePaths.length; i++) {
- signingDetails = collectCertificates(
+ result = getSigningDetails(
+ input,
splitCodePaths[i],
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
+ if (result.isError()) {
+ throw new PackageParser.PackageParserException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
+ }
+
+
+ signingDetails = result.getResult();
}
}
return signingDetails;
@@ -2657,9 +2717,10 @@
}
}
- public static SigningDetails collectCertificates(String baseCodePath, boolean skipVerify,
- boolean isStaticSharedLibrary, @NonNull SigningDetails existingSigningDetails,
- int targetSdk) throws PackageParserException {
+ @CheckResult
+ public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
+ String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary,
+ @NonNull SigningDetails existingSigningDetails, int targetSdk) {
int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
targetSdk);
if (isStaticSharedLibrary) {
@@ -2667,27 +2728,31 @@
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
SigningDetails verified;
- if (skipVerify) {
- // systemDir APKs are already trusted, save time by not verifying
- verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
- baseCodePath, minSignatureScheme);
- } else {
- verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ try {
+ if (skipVerify) {
+ // systemDir APKs are already trusted, save time by not verifying
+ verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+ baseCodePath, minSignatureScheme);
+ } else {
+ verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ }
+ } catch (PackageParserException e) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed collecting certificates for " + baseCodePath, e);
}
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
if (existingSigningDetails == SigningDetails.UNKNOWN) {
- return verified;
+ return input.success(verified);
} else {
if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
- throw new PackageParserException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
baseCodePath + " has mismatched certificates");
}
- return existingSigningDetails;
+ return input.success(existingSigningDetails);
}
}
diff --git a/core/java/android/content/pm/parsing/result/ParseInput.java b/core/java/android/content/pm/parsing/result/ParseInput.java
index d5898b7..0fb18ae 100644
--- a/core/java/android/content/pm/parsing/result/ParseInput.java
+++ b/core/java/android/content/pm/parsing/result/ParseInput.java
@@ -16,6 +16,7 @@
package android.content.pm.parsing.result;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.ChangeId;
@@ -69,6 +70,25 @@
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long RESOURCES_ARSC_COMPRESSED = 132742131;
+
+ /**
+ * TODO(chiuwinson): This is required because PackageManager#getPackageArchiveInfo
+ * cannot read the targetSdk info from the changeId because it requires the
+ * READ_COMPAT_CHANGE_CONFIG which cannot be obtained automatically without entering the
+ * server process. This should be removed once an alternative is found, or if the API
+ * is removed.
+ * @return the targetSdk that this change is gated on (> check), or -1 if disabled
+ */
+ @IntRange(from = -1, to = Integer.MAX_VALUE)
+ public static int getTargetSdkForChange(long changeId) {
+ if (changeId == MISSING_APP_TAG
+ || changeId == EMPTY_INTENT_ACTION_CATEGORY
+ || changeId == RESOURCES_ARSC_COMPRESSED) {
+ return Build.VERSION_CODES.Q;
+ }
+
+ return -1;
+ }
}
<ResultType> ParseResult<ResultType> success(ResultType result);
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index 6115206..14992fb 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -18,12 +18,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingUtils;
+import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.CollectionUtils;
/** @hide */
@@ -61,6 +65,43 @@
private Integer mTargetSdkVersion;
/**
+ * Specifically for {@link PackageManager#getPackageArchiveInfo(String, int)} where
+ * {@link IPlatformCompat} cannot be used because the cross-package READ_COMPAT_CHANGE_CONFIG
+ * permission cannot be obtained.
+ */
+ public static ParseTypeImpl forParsingWithoutPlatformCompat() {
+ return new ParseTypeImpl((changeId, packageName, targetSdkVersion) -> {
+ int gateSdkVersion = DeferredError.getTargetSdkForChange(changeId);
+ if (gateSdkVersion == -1) {
+ return false;
+ }
+ return targetSdkVersion > gateSdkVersion;
+ });
+ }
+
+ /**
+ * Assumes {@link Context#PLATFORM_COMPAT_SERVICE} is available to the caller. For use
+ * with {@link android.content.pm.parsing.ApkLiteParseUtils} or similar where parsing is
+ * done outside of {@link com.android.server.pm.PackageManagerService}.
+ */
+ public static ParseTypeImpl forDefaultParsing() {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ return new ParseTypeImpl((changeId, packageName, targetSdkVersion) -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ try {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ } catch (Exception e) {
+ // This shouldn't happen, but assume enforcement if it does
+ Slog.wtf(ParsingUtils.TAG, "IPlatformCompat query failed", e);
+ return true;
+ }
+ });
+ }
+
+ /**
* @param callback if nullable, fallback to manual targetSdk > Q check
*/
public ParseTypeImpl(@NonNull Callback callback) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c399bc7..0f1c876 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -81,6 +81,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
/**
* Class for accessing an application's resources. This sits on top of the
@@ -140,6 +141,9 @@
@UnsupportedAppUsage
private DrawableInflater mDrawableInflater;
+ /** Used to override the returned adjustments of {@link #getDisplayAdjustments}. */
+ private DisplayAdjustments mOverrideDisplayAdjustments;
+
/** Lock object used to protect access to {@link #mTmpValue}. */
private final Object mTmpValueLock = new Object();
@@ -2055,10 +2059,41 @@
/** @hide */
@UnsupportedAppUsage
public DisplayAdjustments getDisplayAdjustments() {
+ final DisplayAdjustments overrideDisplayAdjustments = mOverrideDisplayAdjustments;
+ if (overrideDisplayAdjustments != null) {
+ return overrideDisplayAdjustments;
+ }
return mResourcesImpl.getDisplayAdjustments();
}
/**
+ * Customize the display adjustments based on the current one in {@link #mResourcesImpl}, in
+ * order to isolate the effect with other instances of {@link Resource} that may share the same
+ * instance of {@link ResourcesImpl}.
+ *
+ * @param override The operation to override the existing display adjustments. If it is null,
+ * the override adjustments will be cleared.
+ * @hide
+ */
+ public void overrideDisplayAdjustments(@Nullable Consumer<DisplayAdjustments> override) {
+ if (override != null) {
+ mOverrideDisplayAdjustments = new DisplayAdjustments(
+ mResourcesImpl.getDisplayAdjustments());
+ override.accept(mOverrideDisplayAdjustments);
+ } else {
+ mOverrideDisplayAdjustments = null;
+ }
+ }
+
+ /**
+ * Return {@code true} if the override display adjustments have been set.
+ * @hide
+ */
+ public boolean hasOverrideDisplayAdjustments() {
+ return mOverrideDisplayAdjustments != null;
+ }
+
+ /**
* Return the current configuration that is in effect for this resource
* object. The returned object should be treated as read-only.
*
diff --git a/core/java/android/debug/AdbNotifications.java b/core/java/android/debug/AdbNotifications.java
index fed5f5f..9f1a5f8 100644
--- a/core/java/android/debug/AdbNotifications.java
+++ b/core/java/android/debug/AdbNotifications.java
@@ -17,11 +17,13 @@
package android.debug;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.UserHandle;
import android.provider.Settings;
@@ -42,8 +44,9 @@
* Builds a notification to show connected state for adb over a transport type.
* @param context the context
* @param transportType the adb transport type.
- * @return a newly created Notification for the transport type.
+ * @return a newly created Notification for the transport type, or null on error.
*/
+ @Nullable
public static Notification createNotification(@NonNull Context context,
byte transportType) {
Resources resources = context.getResources();
@@ -66,10 +69,16 @@
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.setPackage(context.getPackageManager().resolveActivity(intent,
- PackageManager.MATCH_SYSTEM_ONLY).activityInfo.packageName);
- PendingIntent pIntent = PendingIntent.getActivityAsUser(context, 0, intent,
- PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
+ ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent,
+ PackageManager.MATCH_SYSTEM_ONLY);
+ // Settings app may not be available (e.g. device policy manager removes it)
+ PendingIntent pIntent = null;
+ if (resolveInfo != null) {
+ intent.setPackage(resolveInfo.activityInfo.packageName);
+ pIntent = PendingIntent.getActivityAsUser(context, 0, intent,
+ PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
+ }
+
return new Notification.Builder(context, SystemNotificationChannels.DEVELOPER_IMPORTANT)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 2012039..b149d77 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -43,6 +43,10 @@
* through the {@link CameraManager CameraManager}
* interface with {@link CameraManager#getCameraCharacteristics}.</p>
*
+ * <p>When obtained by a client that does not hold the CAMERA permission, some metadata values are
+ * not included. The list of keys that require the permission is given by
+ * {@link #getKeysNeedingPermission}.</p>
+ *
* <p>{@link CameraCharacteristics} objects are immutable.</p>
*
* @see CameraDevice
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index e81c649..230aa04 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -362,6 +362,11 @@
* cameras that can only be used as part of logical multi-camera. These cameras cannot be
* opened directly via {@link #openCamera}</p>
*
+ * <p>Also starting with API level 29, while most basic camera information is still available
+ * even without the CAMERA permission, some values are not available to apps that do not hold
+ * that permission. The keys not available are listed by
+ * {@link CameraCharacteristics#getKeysNeedingPermission}.</p>
+ *
* @param cameraId The id of the camera device to query. This could be either a standalone
* camera ID which can be directly opened by {@link #openCamera}, or a physical camera ID that
* can only used as part of a logical multi-camera.
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 6905f83..d071037 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2182,11 +2182,13 @@
* <p>By using this control, the application gains a simpler way to control zoom, which can
* be a combination of optical and digital zoom. For example, a multi-camera system may
* contain more than one lens with different focal lengths, and the user can use optical
- * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:
- * <em> Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
- * better precision compared to an integer value of {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.
- * </em> Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
- * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} doesn't.</p>
+ * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:</p>
+ * <ul>
+ * <li>Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
+ * better precision compared to an integer value of {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</li>
+ * <li>Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} doesn't.</li>
+ * </ul>
* <p>To illustrate, here are several scenarios of different zoom ratios, crop regions,
* and output streams, for a hypothetical camera device with an active array of size
* <code>(2000,1500)</code>.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index be03502..b546967 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2412,11 +2412,13 @@
* <p>By using this control, the application gains a simpler way to control zoom, which can
* be a combination of optical and digital zoom. For example, a multi-camera system may
* contain more than one lens with different focal lengths, and the user can use optical
- * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:
- * <em> Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
- * better precision compared to an integer value of {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.
- * </em> Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
- * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} doesn't.</p>
+ * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:</p>
+ * <ul>
+ * <li>Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
+ * better precision compared to an integer value of {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</li>
+ * <li>Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} doesn't.</li>
+ * </ul>
* <p>To illustrate, here are several scenarios of different zoom ratios, crop regions,
* and output streams, for a hypothetical camera device with an active array of size
* <code>(2000,1500)</code>.</p>
@@ -3947,14 +3949,24 @@
new Key<Integer>("android.sensor.testPatternMode", int.class);
/**
- * <p>Duration between the start of first row exposure
- * and the start of last row exposure.</p>
- * <p>This is the exposure time skew between the first and last
- * row exposure start times. The first row and the last row are
- * the first and last rows inside of the
+ * <p>Duration between the start of exposure for the first row of the image sensor,
+ * and the start of exposure for one past the last row of the image sensor.</p>
+ * <p>This is the exposure time skew between the first and <code>(last+1)</code> row exposure start times. The
+ * first row and the last row are the first and last rows inside of the
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
- * <p>For typical camera sensors that use rolling shutters, this is also equivalent
- * to the frame readout time.</p>
+ * <p>For typical camera sensors that use rolling shutters, this is also equivalent to the frame
+ * readout time.</p>
+ * <p>If the image sensor is operating in a binned or cropped mode due to the current output
+ * target resolutions, it's possible this skew is reported to be larger than the exposure
+ * time, for example, since it is based on the full array even if a partial array is read
+ * out. Be sure to scale the number to cover the section of the sensor actually being used
+ * for the outputs you care about. So if your output covers N rows of the active array of
+ * height H, scale this value by N/H to get the total skew for that viewport.</p>
+ * <p><em>Note:</em> Prior to Android 11, this field was described as measuring duration from
+ * first to last row of the image sensor, which is not equal to the frame readout time for a
+ * rolling shutter sensor. Implementations generally reported the latter value, so to resolve
+ * the inconsistency, the description has been updated to range from (first, last+1) row
+ * exposure start, instead.</p>
* <p><b>Units</b>: Nanoseconds</p>
* <p><b>Range of valid values:</b><br>
* >= 0 and <
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 4d645e6..0f9c708 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -34,7 +34,6 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -74,6 +73,8 @@
@UnsupportedAppUsage
private static DisplayManagerGlobal sInstance;
+ // Guarded by mLock
+ private boolean mDispatchNativeCallbacks = false;
private final Object mLock = new Object();
@UnsupportedAppUsage
@@ -143,30 +144,38 @@
@UnsupportedAppUsage
public DisplayInfo getDisplayInfo(int displayId) {
synchronized (mLock) {
- DisplayInfo info = null;
- if (mDisplayCache != null) {
- info = mDisplayCache.query(displayId);
- } else {
- try {
- info = mDm.getDisplayInfo(displayId);
- } catch (RemoteException ex) {
- ex.rethrowFromSystemServer();
- }
- }
- if (info == null) {
- return null;
- }
-
- registerCallbackIfNeededLocked();
-
- if (DEBUG) {
- Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
- }
- return info;
+ return getDisplayInfoLocked(displayId);
}
}
/**
+ * Gets information about a particular logical display
+ * See {@link getDisplayInfo}, but assumes that {@link mLock} is held
+ */
+ private @Nullable DisplayInfo getDisplayInfoLocked(int displayId) {
+ DisplayInfo info = null;
+ if (mDisplayCache != null) {
+ info = mDisplayCache.query(displayId);
+ } else {
+ try {
+ info = mDm.getDisplayInfo(displayId);
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
+ if (info == null) {
+ return null;
+ }
+
+ registerCallbackIfNeededLocked();
+
+ if (DEBUG) {
+ Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
+ }
+ return info;
+ }
+
+ /**
* Gets all currently valid logical display ids.
*
* @return An array containing all display ids.
@@ -341,6 +350,20 @@
for (int i = 0; i < numListeners; i++) {
mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
}
+ if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) {
+ // Choreographer only supports a single display, so only dispatch refresh rate
+ // changes for the default display.
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ // We can likely save a binder hop if we attach the refresh rate onto the
+ // listener.
+ DisplayInfo display = getDisplayInfoLocked(displayId);
+ if (display != null) {
+ float refreshRate = display.getMode().getRefreshRate();
+ // Signal native callbacks if we ever set a refresh rate.
+ nSignalNativeCallbacks(refreshRate);
+ }
+ }
+ }
}
}
@@ -800,4 +823,30 @@
public void disableLocalDisplayInfoCaches() {
mDisplayCache = null;
}
+
+ private static native void nSignalNativeCallbacks(float refreshRate);
+
+ // Called from AChoreographer via JNI.
+ // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
+ private void registerNativeChoreographerForRefreshRateCallbacks() {
+ synchronized (mLock) {
+ registerCallbackIfNeededLocked();
+ mDispatchNativeCallbacks = true;
+ DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
+ if (display != null) {
+ // We need to tell AChoreographer instances the current refresh rate so that apps
+ // can get it for free once a callback first registers.
+ float refreshRate = display.getMode().getRefreshRate();
+ nSignalNativeCallbacks(refreshRate);
+ }
+ }
+ }
+
+ // Called from AChoreographer via JNI.
+ // Unregisters AChoreographer from receiving refresh rate callbacks.
+ private void unregisterNativeChoreographerForRefreshRateCallbacks() {
+ synchronized (mLock) {
+ mDispatchNativeCallbacks = false;
+ }
+ }
}
diff --git a/core/java/android/hardware/display/OWNERS b/core/java/android/hardware/display/OWNERS
new file mode 100644
index 0000000..9ca3910
--- /dev/null
+++ b/core/java/android/hardware/display/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+santoscordon@google.com
diff --git a/core/java/android/hardware/input/OWNERS b/core/java/android/hardware/input/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/core/java/android/hardware/input/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 4bed985..f9ed2f8 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -314,6 +314,92 @@
}
@Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof ModuleProperties)) {
+ return false;
+ }
+ ModuleProperties other = (ModuleProperties) obj;
+ if (mId != other.mId) {
+ return false;
+ }
+ if (!mImplementor.equals(other.mImplementor)) {
+ return false;
+ }
+ if (!mDescription.equals(other.mDescription)) {
+ return false;
+ }
+ if (!mUuid.equals(other.mUuid)) {
+ return false;
+ }
+ if (mVersion != other.mVersion) {
+ return false;
+ }
+ if (!mSupportedModelArch.equals(other.mSupportedModelArch)) {
+ return false;
+ }
+ if (mMaxSoundModels != other.mMaxSoundModels) {
+ return false;
+ }
+ if (mMaxKeyphrases != other.mMaxKeyphrases) {
+ return false;
+ }
+ if (mMaxUsers != other.mMaxUsers) {
+ return false;
+ }
+ if (mRecognitionModes != other.mRecognitionModes) {
+ return false;
+ }
+ if (mSupportsCaptureTransition != other.mSupportsCaptureTransition) {
+ return false;
+ }
+ if (mMaxBufferMillis != other.mMaxBufferMillis) {
+ return false;
+ }
+ if (mSupportsConcurrentCapture != other.mSupportsConcurrentCapture) {
+ return false;
+ }
+ if (mPowerConsumptionMw != other.mPowerConsumptionMw) {
+ return false;
+ }
+ if (mReturnsTriggerInEvent != other.mReturnsTriggerInEvent) {
+ return false;
+ }
+ if (mAudioCapabilities != other.mAudioCapabilities) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mId;
+ result = prime * result + mImplementor.hashCode();
+ result = prime * result + mDescription.hashCode();
+ result = prime * result + mUuid.hashCode();
+ result = prime * result + mVersion;
+ result = prime * result + mSupportedModelArch.hashCode();
+ result = prime * result + mMaxSoundModels;
+ result = prime * result + mMaxKeyphrases;
+ result = prime * result + mMaxUsers;
+ result = prime * result + mRecognitionModes;
+ result = prime * result + (mSupportsCaptureTransition ? 1 : 0);
+ result = prime * result + mMaxBufferMillis;
+ result = prime * result + (mSupportsConcurrentCapture ? 1 : 0);
+ result = prime * result + mPowerConsumptionMw;
+ result = prime * result + (mReturnsTriggerInEvent ? 1 : 0);
+ result = prime * result + mAudioCapabilities;
+ return result;
+ }
+
+ @Override
public String toString() {
return "ModuleProperties [id=" + getId() + ", implementor=" + getImplementor()
+ ", description=" + getDescription() + ", uuid=" + getUuid()
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index d3464fd..d8b1f41 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -90,6 +90,7 @@
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.window.WindowMetricsHelper;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInputContentUriToken;
@@ -1438,8 +1439,8 @@
*/
public int getMaxWidth() {
final WindowManager windowManager = getSystemService(WindowManager.class);
- final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
- return windowBounds.width();
+ return WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ windowManager.getCurrentWindowMetrics()).width();
}
/**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7332ede..36ffe50 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -48,6 +48,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -4693,4 +4694,28 @@
Log.d(TAG, "StackLog:" + sb.toString());
}
}
+
+ /**
+ * Simulates a Data Stall for the specified Network.
+ *
+ * <p>The caller must be the owner of the specified Network.
+ *
+ * @param detectionMethod The detection method used to identify the Data Stall.
+ * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds.
+ * @param network The Network for which a Data Stall is being simluated.
+ * @param extras The PersistableBundle of extras included in the Data Stall notification.
+ * @throws SecurityException if the caller is not the owner of the given network.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ android.Manifest.permission.NETWORK_STACK})
+ public void simulateDataStall(int detectionMethod, long timestampMillis,
+ @NonNull Network network, @NonNull PersistableBundle extras) {
+ try {
+ mService.simulateDataStall(detectionMethod, timestampMillis, network, extras);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1434560..69a47f2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.net.ConnectionInfo;
+import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.LinkProperties;
import android.net.Network;
@@ -33,6 +34,7 @@
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.ResultReceiver;
import com.android.internal.net.LegacyVpnInfo;
@@ -227,4 +229,7 @@
void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
IBinder startOrGetTestNetworkService();
+
+ void simulateDataStall(int detectionMethod, long timestampMillis, in Network network,
+ in PersistableBundle extras);
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 52d6fdfb..9ded22f 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -677,16 +677,27 @@
* restrictions.
* @hide
*/
- public void restrictCapabilitesForTestNetwork() {
+ public void restrictCapabilitesForTestNetwork(int creatorUid) {
final long originalCapabilities = mNetworkCapabilities;
final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
final int originalSignalStrength = mSignalStrength;
+ final int originalOwnerUid = getOwnerUid();
+ final int[] originalAdministratorUids = getAdministratorUids();
clearAll();
// Reset the transports to only contain TRANSPORT_TEST.
mTransportTypes = (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
+
+ // Only retain the owner and administrator UIDs if they match the app registering the remote
+ // caller that registered the network.
+ if (originalOwnerUid == creatorUid) {
+ setOwnerUid(creatorUid);
+ }
+ if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
+ setAdministratorUids(new int[] {creatorUid});
+ }
}
/**
diff --git a/core/java/android/os/IIncidentDumpCallback.aidl b/core/java/android/os/IIncidentDumpCallback.aidl
index 09b5b01..d94df34 100644
--- a/core/java/android/os/IIncidentDumpCallback.aidl
+++ b/core/java/android/os/IIncidentDumpCallback.aidl
@@ -25,7 +25,8 @@
*/
oneway interface IIncidentDumpCallback {
/**
- * Dumps section data to the given ParcelFileDescriptor.
+ * Dumps section data to the given ParcelFileDescriptor, which needs to be
+ * closed properly after writing the data.
*/
void onDumpSection(in ParcelFileDescriptor fd);
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index b10abe7..07363ed 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -108,6 +108,7 @@
int getUserBadgeNoBackgroundResId(int userId);
int getUserBadgeLabelResId(int userId);
int getUserBadgeColorResId(int userId);
+ int getUserBadgeDarkColorResId(int userId);
boolean hasBadge(int userId);
boolean isUserUnlocked(int userId);
boolean isUserRunning(int userId);
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index dfa5b26..1a3cf2d 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -550,11 +550,12 @@
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
- if (msg.isInUse()) {
- throw new IllegalStateException(msg + " This message is already in use.");
- }
synchronized (this) {
+ if (msg.isInUse()) {
+ throw new IllegalStateException(msg + " This message is already in use.");
+ }
+
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index e371df0..0ec4fb8 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -1,3 +1,20 @@
+# Haptics
+per-file ExternalVibration.aidl = michaelwr@google.com
+per-file ExternalVibration.java = michaelwr@google.com
+per-file IExternalVibrationController.aidl = michaelwr@google.com
+per-file IExternalVibratorService.aidl = michaelwr@google.com
+per-file IVibratorService.aidl = michaelwr@google.com
+per-file NullVibrator.java = michaelwr@google.com
+per-file SystemVibrator.java = michaelwr@google.com
+per-file VibrationEffect.aidl = michaelwr@google.com
+per-file VibrationEffect.java = michaelwr@google.com
+per-file Vibrator.java = michaelwr@google.com
+
+# PowerManager
+per-file IPowerManager.aidl = michaelwr@google.com, santoscordon@google.com
+per-file PowerManager.java = michaelwr@google.com, santoscordon@google.com
+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
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 187274a..4832e56 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -635,10 +635,11 @@
/**
* Specifies if a user is disallowed from adding new users. This can only be set by device
- * owners, profile owners on the primary user or profile owners of organization-owned managed
- * profiles on the parent profile. The default value is <code>false</code>.
+ * owners or profile owners on the primary user. The default value is <code>false</code>.
* <p>This restriction has no effect on secondary users and managed profiles since only the
* primary user can add other users.
+ * <p> When the device is an organization-owned device provisioned with a managed profile,
+ * this restriction will be set as a base restriction which cannot be removed by any admin.
*
* <p>Key for user restrictions.
* <p>Type: Boolean
@@ -1728,9 +1729,15 @@
* <p>As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method can
* now automatically identify goats using advanced goat recognition technology.</p>
*
- * @return Returns true if the user making this call is a goat.
+ * <p>As of {@link android.os.Build.VERSION_CODES#R}, this method always returns
+ * {@code false} in order to protect goat privacy.</p>
+ *
+ * @return Returns whether the user making this call is a goat.
*/
public boolean isUserAGoat() {
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+ return false;
+ }
return mContext.getPackageManager()
.isPackageAvailable("com.coffeestainstudios.goatsimulator");
}
@@ -2581,8 +2588,8 @@
}
/**
- * Creates a user with the specified name and options. For non-admin users, default user
- * restrictions are going to be applied.
+ * Creates a user with the specified name and options.
+ * Default user restrictions will be applied.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @param name the user's name
@@ -2601,8 +2608,8 @@
}
/**
- * Creates a user with the specified name and options. For non-admin users, default user
- * restrictions will be applied.
+ * Creates a user with the specified name and options.
+ * Default user restrictions will be applied.
*
* <p>Requires {@link android.Manifest.permission#MANAGE_USERS}.
* {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in
@@ -2636,8 +2643,7 @@
}
/**
- * Pre-creates a user of the specified type. For non-admin users, default user
- * restrictions will be applied.
+ * Pre-creates a user of the specified type. Default user restrictions will be applied.
*
* <p>This method can be used by OEMs to "warm" up the user creation by pre-creating some users
* at the first boot, so they when the "real" user is created (for example,
@@ -3662,7 +3668,8 @@
}
/**
- * Returns the badge color for the given user (generally to color a profile's icon's badge).
+ * Returns the light theme badge color for the given user (generally to color a profile's
+ * icon's badge).
*
* <p>To check whether a badge color is expected for the user, first call {@link #hasBadge}.
*
@@ -3682,6 +3689,27 @@
}
/**
+ * Returns the dark theme badge color for the given user (generally to color a profile's icon's
+ * badge).
+ *
+ * <p>To check whether a badge color is expected for the user, first call {@link #hasBadge}.
+ *
+ * @return the color (not the resource ID) to be used for the user's badge
+ * @throws Resources.NotFoundException if no valid badge color exists for this user
+ *
+ * @see #getBadgedIconForUser more information about badging in general
+ * @hide
+ */
+ public @ColorInt int getUserBadgeDarkColor(@UserIdInt int userId) {
+ try {
+ final int resourceId = mService.getUserBadgeDarkColorResId(userId);
+ return Resources.getSystem().getColor(resourceId, null);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the Resource ID of the user's icon badge.
*
* @return the Resource ID of the user's icon badge if it has one; otherwise
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 321dc9e..958c7fb 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -92,10 +92,7 @@
}
}
- if (!result.mDefaultStorage.startLoading()) {
- // TODO(b/146080380): add incremental-specific error code
- throw new IOException("Failed to start loading data for Incremental installation.");
- }
+ result.startLoading();
return result;
}
@@ -144,6 +141,15 @@
}
/**
+ * Starts or re-starts loading of data.
+ */
+ public void startLoading() throws IOException {
+ if (!mDefaultStorage.startLoading()) {
+ throw new IOException("Failed to start loading data for Incremental installation.");
+ }
+ }
+
+ /**
* Resets the states and unbinds storage instances for an installation session.
* TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
*/
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index a1a11ed..16e5156 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -226,9 +226,10 @@
* <p>
* This intent should be launched using
* {@link Activity#startActivityForResult(Intent, int)} so that the user
- * knows which app is requesting to clear cache. The returned result will
- * be {@link Activity#RESULT_OK} if the activity was launched and the user accepted to clear
- * cache, or {@link Activity#RESULT_CANCELED} otherwise.
+ * knows which app is requesting to clear cache. The returned result will be:
+ * {@link Activity#RESULT_OK} if the activity was launched and all cache was cleared,
+ * {@link OsConstants#EIO} if an error occurred while clearing the cache or
+ * {@link Activity#RESULT_CANCELED} otherwise.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index ed429dd..dea932d 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -60,6 +60,7 @@
import libcore.util.EmptyArray;
+import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -68,6 +69,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
@@ -81,6 +83,7 @@
public final class PermissionControllerManager {
private static final String TAG = PermissionControllerManager.class.getSimpleName();
+ private static final long REQUEST_TIMEOUT_MILLIS = 60000;
private static final long UNBIND_TIMEOUT_MILLIS = 10000;
private static final int CHUNK_SIZE = 4 * 1024;
@@ -220,6 +223,11 @@
}
@Override
+ protected long getRequestTimeoutMs() {
+ return REQUEST_TIMEOUT_MILLIS;
+ }
+
+ @Override
protected long getAutoDisconnectTimeoutMs() {
return UNBIND_TIMEOUT_MILLIS;
}
@@ -476,6 +484,20 @@
}
/**
+ * Dump permission controller state.
+ *
+ * @hide
+ */
+ public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) {
+ try {
+ mRemoteService.post(service -> service.asBinder().dump(fd, args))
+ .get(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Log.e(TAG, "Could not get dump", e);
+ }
+ }
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 82a7d78..8ad35e7 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -50,9 +50,11 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -494,6 +496,16 @@
"packageName cannot be null");
onOneTimePermissionSessionTimeout(packageName);
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ checkNotNull(fd, "fd");
+ checkNotNull(writer, "writer");
+
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
+
+ PermissionControllerService.this.dump(fd, writer, args);
+ }
};
}
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 2e00c0c..327bca2 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -1274,8 +1274,6 @@
out.putParcelable(DocumentsContract.EXTRA_RESULT, path);
} else if (METHOD_GET_DOCUMENT_METADATA.equals(method)) {
- enforceReadPermissionInner(documentUri, getCallingPackage(),
- getCallingAttributionTag(), null);
return getDocumentMetadata(documentId);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6c8bd7f..e0bc764 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9936,6 +9936,11 @@
* @hide */
public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
+ /** Timeout for app integrity verification.
+ * @hide */
+ public static final String APP_INTEGRITY_VERIFICATION_TIMEOUT =
+ "app_integrity_verification_timeout";
+
/** Default response code for package verification.
* @hide */
public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
@@ -11956,8 +11961,24 @@
"adaptive_battery_management_enabled";
/**
+ * Whether or not apps are allowed into the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
+ * Type: int (0 for false, 1 for true)
+ * Default: {@value #DEFAULT_ENABLE_RESTRICTED_BUCKET}
+ *
+ * @hide
+ */
+ public static final String ENABLE_RESTRICTED_BUCKET = "enable_restricted_bucket";
+
+ /**
+ * @see #ENABLE_RESTRICTED_BUCKET
+ * @hide
+ */
+ public static final int DEFAULT_ENABLE_RESTRICTED_BUCKET = 1;
+
+ /**
* Whether or not app auto restriction is enabled. When it is enabled, settings app will
- * auto restrict the app if it has bad behavior(e.g. hold wakelock for long time).
+ * auto restrict the app if it has bad behavior (e.g. hold wakelock for long time).
*
* Type: boolean (0 for false, 1 for true)
* Default: 1
@@ -14033,6 +14054,14 @@
"zram_enabled";
/**
+ * Whether the app freezer is enabled on this device.
+ * The value of "enabled" enables the app freezer, "disabled" disables it and
+ * "device_default" will let the system decide whether to enable the freezer or not
+ * @hide
+ */
+ public static final String CACHED_APPS_FREEZER_ENABLED = "cached_apps_freezer";
+
+ /**
* Configuration flags for smart replies in notifications.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 188670d..678f43d 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -455,7 +455,7 @@
* heuristics purposes, but it should not be sent to external servers.
*
* <a name="FieldClassification"></a>
- * <h3>Metrics and field classification</h3
+ * <h3>Metrics and field classification</h3>
*
* <p>The service can call {@link #getFillEventHistory()} to get metrics representing the user
* actions, and then use these metrics to improve its heuristics.
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index d94160c..62becc5 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -86,6 +86,16 @@
*/
public static final @RequestFlags int FLAG_PASSWORD_INPUT_TYPE = 0x4;
+ /**
+ * Indicates the view was not focused.
+ *
+ * <p><b>Note:</b> Defines the flag value to 0x10, because the flag value 0x08 has been defined
+ * in {@link AutofillManager}.</p>
+ *
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -165,7 +175,8 @@
@IntDef(flag = true, prefix = "FLAG_", value = {
FLAG_MANUAL_REQUEST,
FLAG_COMPATIBILITY_MODE_REQUEST,
- FLAG_PASSWORD_INPUT_TYPE
+ FLAG_PASSWORD_INPUT_TYPE,
+ FLAG_VIEW_NOT_FOCUSED
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -187,6 +198,8 @@
return "FLAG_COMPATIBILITY_MODE_REQUEST";
case FLAG_PASSWORD_INPUT_TYPE:
return "FLAG_PASSWORD_INPUT_TYPE";
+ case FLAG_VIEW_NOT_FOCUSED:
+ return "FLAG_VIEW_NOT_FOCUSED";
default: return Integer.toHexString(value);
}
}
@@ -248,7 +261,8 @@
mFlags,
FLAG_MANUAL_REQUEST
| FLAG_COMPATIBILITY_MODE_REQUEST
- | FLAG_PASSWORD_INPUT_TYPE);
+ | FLAG_PASSWORD_INPUT_TYPE
+ | FLAG_VIEW_NOT_FOCUSED);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
onConstructed();
@@ -384,7 +398,8 @@
mFlags,
FLAG_MANUAL_REQUEST
| FLAG_COMPATIBILITY_MODE_REQUEST
- | FLAG_PASSWORD_INPUT_TYPE);
+ | FLAG_PASSWORD_INPUT_TYPE
+ | FLAG_VIEW_NOT_FOCUSED);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
onConstructed();
@@ -405,10 +420,10 @@
};
@DataClass.Generated(
- time = 1588119440090L,
+ time = 1589280816805L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/core/java/android/service/autofill/IInlineSuggestionUi.aidl
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
copy to core/java/android/service/autofill/IInlineSuggestionUi.aidl
index d0f7607..7289853 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
+++ b/core/java/android/service/autofill/IInlineSuggestionUi.aidl
@@ -13,12 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.UserIdInt
+package android.service.autofill;
-data class BubbleXmlEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String
-)
+import android.service.autofill.ISurfacePackageResultCallback;
+
+/**
+ * Interface to interact with a remote inline suggestion UI.
+ *
+ * @hide
+ */
+oneway interface IInlineSuggestionUi {
+ void getSurfacePackage(ISurfacePackageResultCallback callback);
+ void releaseSurfaceControlViewHost();
+}
diff --git a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
index 172cfef..97eb790 100644
--- a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
+++ b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
@@ -18,17 +18,19 @@
import android.content.IntentSender;
import android.os.IBinder;
+import android.service.autofill.IInlineSuggestionUi;
import android.view.SurfaceControlViewHost;
/**
- * Interface to receive events from inline suggestions.
+ * Interface to receive events from a remote inline suggestion UI.
*
* @hide
*/
oneway interface IInlineSuggestionUiCallback {
void onClick();
void onLongClick();
- void onContent(in SurfaceControlViewHost.SurfacePackage surface, int width, int height);
+ void onContent(in IInlineSuggestionUi content, in SurfaceControlViewHost.SurfacePackage surface,
+ int width, int height);
void onError();
void onTransferTouchFocusToImeWindow(in IBinder sourceInputToken, int displayId);
void onStartIntentSender(in IntentSender intentSender);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/core/java/android/service/autofill/ISurfacePackageResultCallback.aidl
similarity index 68%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
copy to core/java/android/service/autofill/ISurfacePackageResultCallback.aidl
index d0f7607..0c2c624 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
+++ b/core/java/android/service/autofill/ISurfacePackageResultCallback.aidl
@@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.UserIdInt
+package android.service.autofill;
-data class BubbleXmlEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String
-)
+import android.view.SurfaceControlViewHost;
+
+/**
+ * Interface to receive a SurfaceControlViewHost.SurfacePackage.
+ *
+ * @hide
+ */
+oneway interface ISurfacePackageResultCallback {
+ void onResult(in SurfaceControlViewHost.SurfacePackage result);
+}
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index 6c22b19..3ea443b 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -33,6 +33,7 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
+import android.util.LruCache;
import android.util.Size;
import android.view.Display;
import android.view.SurfaceControlViewHost;
@@ -40,6 +41,8 @@
import android.view.ViewGroup;
import android.view.WindowManager;
+import java.lang.ref.WeakReference;
+
/**
* A service that renders an inline presentation view given the {@link InlinePresentation}.
*
@@ -65,6 +68,27 @@
private IInlineSuggestionUiCallback mCallback;
+
+ /**
+ * A local LRU cache keeping references to the inflated {@link SurfaceControlViewHost}s, so
+ * they can be released properly when no longer used. Each view needs to be tracked separately,
+ * therefore for simplicity we use the hash code of the value object as key in the cache.
+ */
+ private final LruCache<InlineSuggestionUiImpl, Boolean> mActiveInlineSuggestions =
+ new LruCache<InlineSuggestionUiImpl, Boolean>(30) {
+ @Override
+ public void entryRemoved(boolean evicted, InlineSuggestionUiImpl key,
+ Boolean oldValue,
+ Boolean newValue) {
+ if (evicted) {
+ Log.w(TAG,
+ "Hit max=100 entries in the cache. Releasing oldest one to make "
+ + "space.");
+ key.releaseSurfaceControlViewHost();
+ }
+ }
+ };
+
/**
* If the specified {@code width}/{@code height} is an exact value, then it will be returned as
* is, otherwise the method tries to measure a size that is just large enough to fit the view
@@ -169,8 +193,14 @@
return true;
});
- sendResult(callback, host.getSurfacePackage(), measuredSize.getWidth(),
- measuredSize.getHeight());
+ try {
+ InlineSuggestionUiImpl uiImpl = new InlineSuggestionUiImpl(host, mHandler);
+ mActiveInlineSuggestions.put(uiImpl, true);
+ callback.onContent(new InlineSuggestionUiWrapper(uiImpl), host.getSurfacePackage(),
+ measuredSize.getWidth(), measuredSize.getHeight());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling onContent()");
+ }
} finally {
updateDisplay(Display.DEFAULT_DISPLAY);
}
@@ -181,12 +211,87 @@
callback.sendResult(rendererInfo);
}
- private void sendResult(@NonNull IInlineSuggestionUiCallback callback,
- @Nullable SurfaceControlViewHost.SurfacePackage surface, int width, int height) {
- try {
- callback.onContent(surface, width, height);
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException calling onContent(" + surface + ")");
+ /**
+ * A wrapper class around the {@link InlineSuggestionUiImpl} to ensure it's not strongly
+ * reference by the remote system server process.
+ */
+ private static final class InlineSuggestionUiWrapper extends
+ android.service.autofill.IInlineSuggestionUi.Stub {
+
+ private final WeakReference<InlineSuggestionUiImpl> mUiImpl;
+
+ InlineSuggestionUiWrapper(InlineSuggestionUiImpl uiImpl) {
+ mUiImpl = new WeakReference<>(uiImpl);
+ }
+
+ @Override
+ public void releaseSurfaceControlViewHost() {
+ final InlineSuggestionUiImpl uiImpl = mUiImpl.get();
+ if (uiImpl != null) {
+ uiImpl.releaseSurfaceControlViewHost();
+ }
+ }
+
+ @Override
+ public void getSurfacePackage(ISurfacePackageResultCallback callback) {
+ final InlineSuggestionUiImpl uiImpl = mUiImpl.get();
+ if (uiImpl != null) {
+ uiImpl.getSurfacePackage(callback);
+ }
+ }
+ }
+
+ /**
+ * Keeps track of a SurfaceControlViewHost to ensure it's released when its lifecycle ends.
+ *
+ * <p>This class is thread safe, because all the outside calls are piped into a single
+ * handler thread to be processed.
+ */
+ private final class InlineSuggestionUiImpl {
+
+ @Nullable
+ private SurfaceControlViewHost mViewHost;
+ @NonNull
+ private final Handler mHandler;
+
+ InlineSuggestionUiImpl(SurfaceControlViewHost viewHost, Handler handler) {
+ this.mViewHost = viewHost;
+ this.mHandler = handler;
+ }
+
+ /**
+ * Call {@link SurfaceControlViewHost#release()} to release it. After this, this view is
+ * not usable, and any further calls to the
+ * {@link #getSurfacePackage(ISurfacePackageResultCallback)} will get {@code null} result.
+ */
+ public void releaseSurfaceControlViewHost() {
+ mHandler.post(() -> {
+ if (mViewHost == null) {
+ return;
+ }
+ Log.v(TAG, "Releasing inline suggestion view host");
+ mViewHost.release();
+ mViewHost = null;
+ InlineSuggestionRenderService.this.mActiveInlineSuggestions.remove(
+ InlineSuggestionUiImpl.this);
+ Log.v(TAG, "Removed the inline suggestion from the cache, current size="
+ + InlineSuggestionRenderService.this.mActiveInlineSuggestions.size());
+ });
+ }
+
+ /**
+ * Sends back a new {@link android.view.SurfaceControlViewHost.SurfacePackage} if the view
+ * is not released, {@code null} otherwise.
+ */
+ public void getSurfacePackage(ISurfacePackageResultCallback callback) {
+ Log.d(TAG, "getSurfacePackage");
+ mHandler.post(() -> {
+ try {
+ callback.onResult(mViewHost == null ? null : mViewHost.getSurfacePackage());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling onSurfacePackage");
+ }
+ });
}
}
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index 0a29edc..09d1bb9 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -21,6 +21,8 @@
import android.os.Bundle;
import android.view.WindowInsets;
+import com.android.internal.R;
+
/**
* The Activity used by the {@link DreamService} to draw screensaver content
* on the screen. This activity runs in dream application's process, but is started by a
@@ -56,8 +58,20 @@
if (callback != null) {
callback.onActivityCreated(this);
}
+ }
+ @Override
+ public void onResume() {
+ super.onResume();
// Hide all insets (nav bar, status bar, etc) when the dream is showing
getWindow().getInsetsController().hide(WindowInsets.Type.systemBars());
+ overridePendingTransition(R.anim.dream_activity_open_enter,
+ R.anim.dream_activity_open_exit);
+ }
+
+ @Override
+ public void finishAndRemoveTask() {
+ super.finishAndRemoveTask();
+ overridePendingTransition(0, R.anim.dream_activity_close_exit);
}
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 337027e..d2dfb29 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1052,7 +1052,6 @@
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
@@ -1076,8 +1075,12 @@
@Override
public void onViewDetachedFromWindow(View v) {
- mActivity = null;
- finish();
+ if (mActivity == null || !mActivity.isChangingConfigurations()) {
+ // Only stop the dream if the view is not detached by relaunching
+ // activity for configuration changes.
+ mActivity = null;
+ finish();
+ }
}
});
}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 92f3538..aea94bf 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -283,8 +283,8 @@
} else {
serviceIntent.setComponent(mServiceComponent);
}
-
- if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(serviceIntent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES)) {
Log.e(TAG, "bind to recognition service failed");
mConnection = null;
mService = null;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 4469fdb..8db1703 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -104,6 +104,14 @@
private int mCachedAppHeightCompat;
/**
+ * Indicates that the application is started in a different rotation than the real display, so
+ * the display information may be adjusted. That ensures the methods {@link #getRotation},
+ * {@link #getRealSize}, {@link #getRealMetrics}, and {@link #getCutout} are consistent with how
+ * the application window is laid out.
+ */
+ private boolean mMayAdjustByFixedRotation;
+
+ /**
* The default Display id, which is the id of the primary display assuming there is one.
*/
public static final int DEFAULT_DISPLAY = 0;
@@ -804,7 +812,9 @@
public int getRotation() {
synchronized (this) {
updateDisplayInfoLocked();
- return mDisplayInfo.rotation;
+ return mMayAdjustByFixedRotation
+ ? getDisplayAdjustments().getRotation(mDisplayInfo.rotation)
+ : mDisplayInfo.rotation;
}
}
@@ -828,7 +838,9 @@
public DisplayCutout getCutout() {
synchronized (this) {
updateDisplayInfoLocked();
- return mDisplayInfo.displayCutout;
+ return mMayAdjustByFixedRotation
+ ? getDisplayAdjustments().getDisplayCutout(mDisplayInfo.displayCutout)
+ : mDisplayInfo.displayCutout;
}
}
@@ -1140,6 +1152,9 @@
updateDisplayInfoLocked();
outSize.x = mDisplayInfo.logicalWidth;
outSize.y = mDisplayInfo.logicalHeight;
+ if (mMayAdjustByFixedRotation) {
+ getDisplayAdjustments().adjustSize(outSize, mDisplayInfo.rotation);
+ }
}
}
@@ -1159,6 +1174,9 @@
updateDisplayInfoLocked();
mDisplayInfo.getLogicalMetrics(outMetrics,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ if (mMayAdjustByFixedRotation) {
+ getDisplayAdjustments().adjustMetrics(outMetrics, mDisplayInfo.rotation);
+ }
}
}
@@ -1225,6 +1243,9 @@
}
}
}
+
+ mMayAdjustByFixedRotation = mResources != null
+ && mResources.hasOverrideDisplayAdjustments();
}
private void updateCachedAppSizeIfNeededLocked() {
@@ -1243,9 +1264,12 @@
public String toString() {
synchronized (this) {
updateDisplayInfoLocked();
- mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments());
+ final DisplayAdjustments adjustments = getDisplayAdjustments();
+ mDisplayInfo.getAppMetrics(mTempMetrics, adjustments);
return "Display id " + mDisplayId + ": " + mDisplayInfo
- + ", " + mTempMetrics + ", isValid=" + mIsValid;
+ + (mMayAdjustByFixedRotation
+ ? (", " + adjustments.getFixedRotationAdjustments() + ", ") : ", ")
+ + mTempMetrics + ", isValid=" + mIsValid;
}
}
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index 27c2d5c..c726bee 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -21,6 +21,10 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.graphics.Point;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DisplayMetrics;
import java.util.Objects;
@@ -30,6 +34,7 @@
private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
private final Configuration mConfiguration = new Configuration(Configuration.EMPTY);
+ private FixedRotationAdjustments mFixedRotationAdjustments;
@UnsupportedAppUsage
public DisplayAdjustments() {
@@ -44,6 +49,7 @@
public DisplayAdjustments(@NonNull DisplayAdjustments daj) {
setCompatibilityInfo(daj.mCompatInfo);
mConfiguration.setTo(daj.getConfiguration());
+ mFixedRotationAdjustments = daj.mFixedRotationAdjustments;
}
@UnsupportedAppUsage
@@ -84,11 +90,78 @@
return mConfiguration;
}
+ public void setFixedRotationAdjustments(FixedRotationAdjustments fixedRotationAdjustments) {
+ mFixedRotationAdjustments = fixedRotationAdjustments;
+ }
+
+ public FixedRotationAdjustments getFixedRotationAdjustments() {
+ return mFixedRotationAdjustments;
+ }
+
+ /** Returns {@code false} if the width and height of display should swap. */
+ private boolean noFlip(@Surface.Rotation int realRotation) {
+ final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
+ if (rotationAdjustments == null) {
+ return true;
+ }
+ // Check if the delta is rotated by 90 degrees.
+ return (realRotation - rotationAdjustments.mRotation + 4) % 2 == 0;
+ }
+
+ /** Adjusts the given size if possible. */
+ public void adjustSize(@NonNull Point size, @Surface.Rotation int realRotation) {
+ if (noFlip(realRotation)) {
+ return;
+ }
+ final int w = size.x;
+ size.x = size.y;
+ size.y = w;
+ }
+
+ /** Adjusts the given metrics if possible. */
+ public void adjustMetrics(@NonNull DisplayMetrics metrics, @Surface.Rotation int realRotation) {
+ if (noFlip(realRotation)) {
+ return;
+ }
+ int w = metrics.widthPixels;
+ metrics.widthPixels = metrics.heightPixels;
+ metrics.heightPixels = w;
+
+ w = metrics.noncompatWidthPixels;
+ metrics.noncompatWidthPixels = metrics.noncompatHeightPixels;
+ metrics.noncompatHeightPixels = w;
+
+ float x = metrics.xdpi;
+ metrics.xdpi = metrics.ydpi;
+ metrics.ydpi = x;
+
+ x = metrics.noncompatXdpi;
+ metrics.noncompatXdpi = metrics.noncompatYdpi;
+ metrics.noncompatYdpi = x;
+ }
+
+ /** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */
+ @Nullable
+ public DisplayCutout getDisplayCutout(@Nullable DisplayCutout realCutout) {
+ final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
+ return rotationAdjustments != null && rotationAdjustments.mRotatedDisplayCutout != null
+ ? rotationAdjustments.mRotatedDisplayCutout
+ : realCutout;
+ }
+
+ /** Returns the adjusted rotation if available. Otherwise the original rotation is returned. */
+ @Surface.Rotation
+ public int getRotation(@Surface.Rotation int realRotation) {
+ final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
+ return rotationAdjustments != null ? rotationAdjustments.mRotation : realRotation;
+ }
+
@Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + Objects.hashCode(mCompatInfo);
hash = hash * 31 + Objects.hashCode(mConfiguration);
+ hash = hash * 31 + Objects.hashCode(mFixedRotationAdjustments);
return hash;
}
@@ -98,7 +171,82 @@
return false;
}
DisplayAdjustments daj = (DisplayAdjustments)o;
- return Objects.equals(daj.mCompatInfo, mCompatInfo) &&
- Objects.equals(daj.mConfiguration, mConfiguration);
+ return Objects.equals(daj.mCompatInfo, mCompatInfo)
+ && Objects.equals(daj.mConfiguration, mConfiguration)
+ && Objects.equals(daj.mFixedRotationAdjustments, mFixedRotationAdjustments);
+ }
+
+ /**
+ * An application can be launched in different rotation than the real display. This class
+ * provides the information to adjust the values returned by {@link #Display}.
+ * @hide
+ */
+ public static class FixedRotationAdjustments implements Parcelable {
+ /** The application-based rotation. */
+ @Surface.Rotation
+ final int mRotation;
+
+ /** Non-null if the device has cutout. */
+ @Nullable
+ final DisplayCutout mRotatedDisplayCutout;
+
+ public FixedRotationAdjustments(@Surface.Rotation int rotation, DisplayCutout cutout) {
+ mRotation = rotation;
+ mRotatedDisplayCutout = cutout;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = hash * 31 + mRotation;
+ hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof FixedRotationAdjustments)) {
+ return false;
+ }
+ final FixedRotationAdjustments other = (FixedRotationAdjustments) o;
+ return mRotation == other.mRotation
+ && Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout);
+ }
+
+ @Override
+ public String toString() {
+ return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation)
+ + " cutout=" + mRotatedDisplayCutout + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRotation);
+ dest.writeTypedObject(
+ new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags);
+ }
+
+ private FixedRotationAdjustments(Parcel in) {
+ mRotation = in.readInt();
+ final DisplayCutout.ParcelableWrapper cutoutWrapper =
+ in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR);
+ mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null;
+ }
+
+ public static final Creator<FixedRotationAdjustments> CREATOR =
+ new Creator<FixedRotationAdjustments>() {
+ public FixedRotationAdjustments createFromParcel(Parcel in) {
+ return new FixedRotationAdjustments(in);
+ }
+
+ public FixedRotationAdjustments[] newArray(int size) {
+ return new FixedRotationAdjustments[size];
+ }
+ };
}
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 926d8fc..0410c90 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -336,7 +336,7 @@
* an input channel where the client can receive input.
*/
void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window,
- in IBinder hostInputToken, int flags, out InputChannel outInputChannel);
+ in IBinder hostInputToken, int flags, int type, out InputChannel outInputChannel);
/**
* Update the flags on an input channel associated with a particular surface.
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index dbbe4b6..a480072 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -208,26 +208,6 @@
}
/**
- * Called by {@link ViewRootImpl} to feedback the state of the screen for this view.
- * @param newScreenState The new state of the screen. Can be either
- * {@link View#SCREEN_STATE_ON} or {@link View#SCREEN_STATE_OFF}
- */
- @UiThread
- void onScreenStateChanged(int newScreenState) {
- if (!getImmDelegate().isCurrentRootView(mViewRootImpl)) {
- return;
- }
- // Close input connection and IME when the screen is turn off for security concern.
- if (newScreenState == View.SCREEN_STATE_OFF && mServedView != null) {
- if (DEBUG) {
- Log.d(TAG, "onScreenStateChanged, disconnect input when screen turned off");
- }
- mNextServedView = null;
- mViewRootImpl.dispatchCheckFocus();
- }
- }
-
- /**
* @param windowAttribute {@link WindowManager.LayoutParams} to be checked.
* @return Whether the window is in local focus mode or not.
*/
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 9dfdd06..3215b7c 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -21,6 +21,7 @@
import android.annotation.UiThread;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.Trace;
import android.util.SparseArray;
import android.view.InsetsController.AnimationType;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
@@ -60,6 +61,9 @@
@Override
public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
+ "InsetsAsyncAnimation: " + WindowInsets.Type.toString(runner.getTypes()),
+ runner.getTypes());
releaseControls(mControl.getControls());
mMainThreadHandler.post(() ->
mOuterCallbacks.notifyFinished(InsetsAnimationThreadControlRunner.this, shown));
@@ -93,7 +97,11 @@
mOuterCallbacks = controller;
mControl = new InsetsAnimationControlImpl(controls, frame, state, listener,
types, mCallbacks, durationMs, interpolator, animationType);
- InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
+ InsetsAnimationThread.getHandler().post(() -> {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
+ "InsetsAsyncAnimation: " + WindowInsets.Type.toString(types), types);
+ listener.onReady(mControl, types);
+ });
}
private void releaseControls(SparseArray<InsetsSourceControl> controls) {
@@ -102,15 +110,6 @@
}
}
- private SparseArray<InsetsSourceControl> copyControls(
- SparseArray<InsetsSourceControl> controls) {
- SparseArray<InsetsSourceControl> copy = new SparseArray<>(controls.size());
- for (int i = 0; i < controls.size(); i++) {
- copy.append(controls.keyAt(i), new InsetsSourceControl(controls.valueAt(i)));
- }
- return copy;
- }
-
@Override
@UiThread
public int getTypes() {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index a135b0c..d12a122 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -35,6 +35,7 @@
import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
+import android.os.Trace;
import android.util.ArraySet;
import android.util.Pair;
import android.util.SparseArray;
@@ -567,11 +568,15 @@
private void updateState(InsetsState newState) {
mState.setDisplayFrame(newState.getDisplayFrame());
for (int i = newState.getSourcesCount() - 1; i >= 0; i--) {
- InsetsSource source = newState.sourceAt(i);
- getSourceConsumer(source.getType()).updateSource(source);
+ final InsetsSource source = newState.sourceAt(i);
+ final int type = source.getType();
+ final InsetsSourceConsumer consumer = getSourceConsumer(type);
+ consumer.updateSource(source);
+ mHost.updateCompatSysUiVisibility(type, source.isVisible(),
+ consumer.getControl() != null);
}
for (int i = mState.getSourcesCount() - 1; i >= 0; i--) {
- InsetsSource source = mState.sourceAt(i);
+ final InsetsSource source = mState.sourceAt(i);
if (newState.peekSource(source.getType()) == null) {
mState.removeSource(source.getType());
}
@@ -667,7 +672,7 @@
if (hideTypes[0] != 0) {
applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
}
- if (hasControl) {
+ if (hasControl && mRequestedState.getSourcesCount() > 0) {
// We might have changed our requested visibilities while we don't have the control,
// so we need to update our requested state once we have control. Otherwise, our
// requested state at the server side might be incorrect.
@@ -1006,14 +1011,6 @@
}
/**
- * @see ViewRootImpl#updateCompatSysUiVisibility(int, boolean, boolean)
- */
- public void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
- boolean hasControl) {
- mHost.updateCompatSysUiVisibility(type, visible, hasControl);
- }
-
- /**
* Called when current window gains focus.
*/
public void onWindowFocusGained() {
@@ -1065,9 +1062,16 @@
if (consumer.getControl() != null) {
final InsetsSource localSource = mState.getSource(type);
if (!localSource.equals(mRequestedState.peekSource(type))) {
+ // Our requested state is stale. Update it here and send it to window manager.
mRequestedState.addSource(new InsetsSource(localSource));
changed = true;
}
+ if (!localSource.equals(mLastDispatchedState.peekSource(type))) {
+ // The server state is not what we expected. This can happen while we don't have
+ // the control. Since we have the control now, we need to send our request again
+ // to modify the server state.
+ changed = true;
+ }
}
}
if (!changed) {
@@ -1117,7 +1121,7 @@
* Cancel on-going animation to show/hide {@link InsetsType}.
*/
@VisibleForTesting
- public void cancelExistingAnimation() {
+ public void cancelExistingAnimations() {
cancelExistingControllers(all());
}
@@ -1136,6 +1140,8 @@
if (controller.isCancelled()) {
return;
}
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
+ "InsetsAnimation: " + WindowInsets.Type.toString(types), types);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == controller) {
@@ -1152,6 +1158,9 @@
@VisibleForTesting
public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
+ "InsetsAnimation: " + WindowInsets.Type.toString(animation.getTypeMask()),
+ animation.getTypeMask());
mHost.dispatchWindowInsetsAnimationEnd(animation);
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 58ec9ec..a0cdcfe 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -200,29 +200,12 @@
}
boolean applyLocalVisibilityOverride() {
- return applyLocalVisibilityOverride(false /* notifyWithoutControl */);
- }
-
- /**
- * @param notifyWithoutControl set it true when the caller wants to notify the visibility
- * changes even if the consumer doesn't have the control.
- * @return true if it needs to notify the visibility changes to the controller
- */
- private boolean applyLocalVisibilityOverride(boolean notifyWithoutControl) {
- InsetsSource source = mState.peekSource(mType);
- final boolean isVisible = source != null && source.isVisible();
- final boolean hasControl = mSourceControl != null;
-
- // We still need to let the legacy app know the visibility change even if we don't have the
- // control.
- mController.updateCompatSysUiVisibility(
- mType, hasControl ? mRequestedVisible : isVisible, hasControl);
// If we don't have control, we are not able to change the visibility.
- if (!hasControl) {
- return notifyWithoutControl;
+ if (mSourceControl == null) {
+ return false;
}
- if (isVisible == mRequestedVisible) {
+ if (mState.getSource(mType).isVisible() == mRequestedVisible) {
return false;
}
mState.getSource(mType).setVisible(mRequestedVisible);
@@ -302,9 +285,7 @@
mRequestedVisible = requestedVisible;
mIsAnimationPending = false;
}
- // We need to notify the visibility changed even if we don't have mSourceControl in order
- // to update color views.
- if (applyLocalVisibilityOverride(true /* notifyWithoutControl */)) {
+ if (applyLocalVisibilityOverride()) {
mController.notifyVisibilityChanged();
}
}
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
new file mode 100644
index 0000000..7b60f2e
--- /dev/null
+++ b/core/java/android/view/OWNERS
@@ -0,0 +1,15 @@
+# Display
+per-file Display.java = michaelwr@google.com, santoscordon@google.com
+per-file DisplayInfo.java = michaelwr@google.com, santoscordon@google.com
+
+# Haptics
+per-file HapticFeedbackConstants.java = michaelwr@google.com, santoscordon@google.com
+
+# Input
+per-file IInputMonitorHost.aidl = michaelwr@google.com, svv@google.com
+per-file Input*.java = michaelwr@google.com, svv@google.com
+per-file Input*.aidl = michaelwr@google.com, svv@google.com
+per-file KeyEvent.java = michaelwr@google.com, svv@google.com
+per-file MotionEvent.java = michaelwr@google.com, svv@google.com
+per-file PointerIcon.java = michaelwr@google.com, svv@google.com
+per-file SimulatedDpad.java = michaelwr@google.com, svv@google.com
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c0c29eb..9109f50 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -220,6 +220,8 @@
private static native long nativeAcquireFrameRateFlexibilityToken();
private static native void nativeReleaseFrameRateFlexibilityToken(long token);
+ private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject,
+ int transformHint);
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -2307,6 +2309,39 @@
}
/**
+ * Provide the graphic producer a transform hint if the layer and its children are
+ * in an orientation different from the display's orientation. The caller is responsible
+ * for clearing this transform hint if the layer is no longer in a fixed orientation.
+ *
+ * The transform hint is used to prevent allocating a buffer of different size when a
+ * layer is rotated. The producer can choose to consume the hint and allocate the buffer
+ * with the same size.
+ *
+ * @return This Transaction.
+ * @hide
+ */
+ @NonNull
+ public Transaction setFixedTransformHint(@NonNull SurfaceControl sc,
+ @Surface.Rotation int transformHint) {
+ checkPreconditions(sc);
+ nativeSetFixedTransformHint(mNativeObject, sc.mNativeObject, transformHint);
+ return this;
+ }
+
+ /**
+ * Clearing any transform hint if set on this layer.
+ *
+ * @return This Transaction.
+ * @hide
+ */
+ @NonNull
+ public Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
+ checkPreconditions(sc);
+ nativeSetFixedTransformHint(mNativeObject, sc.mNativeObject, -1/* INVALID_ROTATION */);
+ return this;
+ }
+
+ /**
* Set the Z-order for a given SurfaceControl, relative to it's siblings.
* If two siblings share the same Z order the ordering is undefined. Surfaces
* with a negative Z will be placed below the parent surface.
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 7086dc0..3850781 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -275,12 +275,4 @@
// ViewRoot will release mSurfaceControl for us.
mViewRoot.die(false /* immediate */);
}
-
- /**
- * Tell this viewroot to clean itself up.
- * @hide
- */
- public void die() {
- mViewRoot.die(false /* immediate */);
- }
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index db6fe0f..bd811fc 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -134,6 +134,23 @@
// we need to preserve the old one until the new one has drawn.
SurfaceControl mDeferredDestroySurfaceControl;
SurfaceControl mBackgroundControl;
+
+ /**
+ * We use this lock in SOME cases when reading or writing SurfaceControl,
+ * but use the following model so that the RenderThread can run locklessly
+ * in the position up-date case.
+ *
+ * 1. UI Thread can read from mSurfaceControl (use in Transactions) without
+ * holding the lock.
+ * 2. UI Thread will hold the lock when writing to mSurfaceControl (calling release
+ * or remove).
+ * 3. Render thread will also hold the lock when writing to mSurfaceControl (e.g.
+ * calling release from positionLost).
+ * 3. RenderNode.PositionUpdateListener::positionChanged will only be called
+ * when the UI thread is paused (blocked on the Render thread).
+ * 4. positionChanged thus will not be required to hold the lock as the
+ * UI thread is blocked, and the other writer is the RT itself.
+ */
final Object mSurfaceControlLock = new Object();
final Rect mTmpRect = new Rect();
@@ -1297,15 +1314,19 @@
(viewRoot != null ? viewRoot.getBLASTSyncTransaction() : mRtTransaction) :
mRtTransaction;
- if (frameNumber > 0 && viewRoot != null && !useBLAST) {
- if (viewRoot.mSurface.isValid()) {
- mRtTransaction.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frameNumber);
- }
- }
- t.hide(mSurfaceControl);
-
+ /**
+ * positionLost can be called while UI thread is un-paused so we
+ * need to hold the lock here.
+ */
synchronized (mSurfaceControlLock) {
+ if (frameNumber > 0 && viewRoot != null && !useBLAST) {
+ if (viewRoot.mSurface.isValid()) {
+ mRtTransaction.deferTransactionUntil(mSurfaceControl,
+ viewRoot.getRenderSurfaceControl(), frameNumber);
+ }
+ }
+ t.hide(mSurfaceControl);
+
if (mRtReleaseSurfaces) {
mRtReleaseSurfaces = false;
mRtTransaction.remove(mSurfaceControl);
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 69d37ab..0d2d4d1 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -416,7 +416,7 @@
com.android.internal.R.dimen.config_ambiguousGestureMultiplier,
multiplierValue,
true /*resolveRefs*/);
- mAmbiguousGestureMultiplier = multiplierValue.getFloat();
+ mAmbiguousGestureMultiplier = Math.max(1.0f, multiplierValue.getFloat());
// Size of the screen in bytes, in ARGB_8888 format
final WindowManager windowManager = context.getSystemService(WindowManager.class);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 42f11c1..d928356 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -704,6 +704,11 @@
// draw returns.
private SurfaceControl.Transaction mRtBLASTSyncTransaction = new SurfaceControl.Transaction();
+ // Keeps track of whether the WM requested us to use BLAST Sync when calling relayout.
+ // We use this to make sure we don't send the WM transactions from an internal BLAST sync
+ // (e.g. SurfaceView)
+ private boolean mSendNextFrameToWm = false;
+
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
private String mTag = TAG;
@@ -1491,7 +1496,6 @@
final int newScreenState = toViewScreenState(newDisplayState);
if (oldScreenState != newScreenState) {
mView.dispatchScreenStateChanged(newScreenState);
- mImeFocusController.onScreenStateChanged(newScreenState);
}
if (oldDisplayState == Display.STATE_OFF) {
// Draw was suppressed so we need to for it to happen here.
@@ -1972,6 +1976,10 @@
mCompatibleVisibilityInfo.globalVisibility =
(mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE)
| (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ MSG_DISPATCH_SYSTEM_UI_VISIBILITY, mCompatibleVisibilityInfo));
+ }
if (mAttachInfo.mKeepScreenOn != oldScreenOn
|| mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
|| mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
@@ -2025,7 +2033,7 @@
info.globalVisibility |= systemUiFlag;
}
if (mDispatchedSystemUiVisibility != info.globalVisibility) {
- scheduleTraversals();
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, info));
}
}
@@ -2473,9 +2481,6 @@
mAttachInfo.mForceReportNewAttributes = false;
params = lp;
}
- if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- handleDispatchSystemUiVisibilityChanged(mCompatibleVisibilityInfo);
- }
if (mFirst || mAttachInfo.mViewVisibilityChanged) {
mAttachInfo.mViewVisibilityChanged = false;
@@ -3053,6 +3058,7 @@
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) {
reportNextDraw();
setUseBLASTSyncTransaction();
+ mSendNextFrameToWm = true;
}
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
@@ -3762,7 +3768,7 @@
if (needFrameCompleteCallback) {
final Handler handler = mAttachInfo.mHandler;
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
- finishBLASTSync(!reportNextDraw);
+ finishBLASTSync(!mSendNextFrameToWm);
handler.postAtFrontOfQueue(() -> {
if (reportNextDraw) {
// TODO: Use the frame number
@@ -3784,7 +3790,7 @@
// so if we are BLAST syncing we make sure the previous draw has
// totally finished.
if (mAttachInfo.mThreadedRenderer != null) {
- mAttachInfo.mThreadedRenderer.fence();
+ mAttachInfo.mThreadedRenderer.pause();
}
mNextReportConsumeBLAST = true;
@@ -4624,6 +4630,8 @@
setAccessibilityFocus(null, null);
+ mInsetsController.cancelExistingAnimations();
+
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
@@ -4636,14 +4644,17 @@
mInputQueueCallback = null;
mInputQueue = null;
}
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
try {
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
+ // Dispose receiver would dispose client InputChannel, too. That could send out a socket
+ // broken event, so we need to unregister the server InputChannel when removing window to
+ // prevent server side receive the event and prompt error.
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ }
mDisplayManager.unregisterDisplayListener(mDisplayListener);
@@ -9752,6 +9763,7 @@
}
private void finishBLASTSync(boolean apply) {
+ mSendNextFrameToWm = false;
if (mNextReportConsumeBLAST) {
mNextReportConsumeBLAST = false;
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index d8bf58f..9674a80 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -104,10 +104,10 @@
@Override
public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
+ if (mViewRoot.mView == null) {
+ throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
+ }
if (mApplier == null) {
- if (mViewRoot.mView == null) {
- throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
- }
mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
}
if (mViewRoot.mView.isHardwareAccelerated()) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index aad1c60..4d6b72f 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -1328,30 +1328,36 @@
}
}
- static String toString(@InsetsType int type) {
- switch (type) {
- case STATUS_BARS:
- return "statusBars";
- case NAVIGATION_BARS:
- return "navigationBars";
- case CAPTION_BAR:
- return "captionBar";
- case IME:
- return "ime";
- case SYSTEM_GESTURES:
- return "systemGestures";
- case MANDATORY_SYSTEM_GESTURES:
- return "mandatorySystemGestures";
- case TAPPABLE_ELEMENT:
- return "tappableElement";
- case DISPLAY_CUTOUT:
- return "displayCutout";
- case WINDOW_DECOR:
- return "windowDecor";
- default:
- throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
- + " type=" + type);
+ static String toString(@InsetsType int types) {
+ StringBuilder result = new StringBuilder();
+ if ((types & STATUS_BARS) != 0) {
+ result.append("statusBars |");
}
+ if ((types & NAVIGATION_BARS) != 0) {
+ result.append("navigationBars |");
+ }
+ if ((types & IME) != 0) {
+ result.append("ime |");
+ }
+ if ((types & SYSTEM_GESTURES) != 0) {
+ result.append("systemGestures |");
+ }
+ if ((types & MANDATORY_SYSTEM_GESTURES) != 0) {
+ result.append("mandatorySystemGestures |");
+ }
+ if ((types & TAPPABLE_ELEMENT) != 0) {
+ result.append("tappableElement |");
+ }
+ if ((types & DISPLAY_CUTOUT) != 0) {
+ result.append("displayCutout |");
+ }
+ if ((types & WINDOW_DECOR) != 0) {
+ result.append("windowDecor |");
+ }
+ if (result.length() > 0) {
+ result.delete(result.length() - 2, result.length());
+ }
+ return result.toString();
}
private Type() {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9a3c706..7607127 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1162,7 +1162,7 @@
/**
* Window type: shows directly above the keyguard. The layer is
- * reserved for screenshot region selection. These windows must not take input focus.
+ * reserved for screenshot animation, region selection and UI.
* In multiuser systems shows only on the owning user's window.
* @hide
*/
@@ -1217,6 +1217,14 @@
public static final int TYPE_STATUS_BAR_ADDITIONAL = FIRST_SYSTEM_WINDOW + 41;
/**
+ * Similar to TYPE_APPLICATION_OVERLAY, but trusted to overlay other windows since it is
+ * is coming from the system.
+ * @hide
+ */
+ // TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready.
+ public static final int TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
index 86ef879..d96c5c8 100644
--- a/core/java/android/view/WindowMetrics.java
+++ b/core/java/android/view/WindowMetrics.java
@@ -48,22 +48,19 @@
* and display cutout areas. The value reported by {@link Display#getSize(Point)} can be
* obtained by using:
* <pre class="prettyprint">
- * final WindowMetrics metrics = windowManager.getCurrentMetrics();
+ * final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
* // Gets all excluding insets
* final WindowInsets windowInsets = metrics.getWindowInsets();
- * Insets insets = windowInsets.getInsets(WindowInsets.Type.navigationBars());
- * final DisplayCutout cutout = windowInsets.getCutout();
- * if (cutout != null) {
- * final Insets cutoutSafeInsets = Insets.of(cutout.getSafeInsetsLeft(), ...);
- * insets = insets.max(insets, cutoutSafeInsets);
- * }
+ * Insets insets = windowInsets.getInsetsIgnoreVisibility(WindowInsets.Type.navigationBars()
+ * | WindowInsets.Type.displayCutout());
*
* int insetsWidth = insets.right + insets.left;
* int insetsHeight = insets.top + insets.bottom;
*
* // Legacy size that Display#getSize reports
- * final Size legacySize = new Size(metrics.getWidth() - insetsWidth,
- * metrics.getHeight() - insetsHeight);
+ * final Rect bounds = metrics.getBounds();
+ * final Size legacySize = new Size(bounds.width() - insetsWidth,
+ * bounds.height() - insetsHeight);
* </pre>
* </p>
*
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 95d6d65..d20ffb3 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -41,6 +41,7 @@
private final static String TAG = "WindowlessWindowManager";
private class State {
+ //TODO : b/150190730 we should create it when view show and release it when view invisible.
SurfaceControl mSurfaceControl;
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
int mDisplayId;
@@ -142,7 +143,7 @@
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
try {
mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
- outInputChannel);
+ attrs.type, outInputChannel);
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
}
@@ -190,6 +191,7 @@
throw new IllegalArgumentException(
"Invalid window token (never added or removed already)");
}
+
try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
t.remove(state.mSurfaceControl).apply();
}
@@ -239,21 +241,19 @@
}
WindowManager.LayoutParams attrs = state.mParams;
- final Rect surfaceInsets = attrs.surfaceInsets;
- int width = surfaceInsets != null ?
- attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width;
- int height = surfaceInsets != null ?
- attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
-
- t.setBufferSize(sc, width, height)
- .setOpaque(sc, isOpaque(attrs));
if (viewFlags == View.VISIBLE) {
- t.show(sc);
+ final Rect surfaceInsets = attrs.surfaceInsets;
+ int width = surfaceInsets != null
+ ? attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width;
+ int height = surfaceInsets != null
+ ? attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
+
+ t.setBufferSize(sc, width, height).setOpaque(sc, isOpaque(attrs)).show(sc).apply();
+ outSurfaceControl.copyFrom(sc);
} else {
- t.hide(sc);
+ t.hide(sc).apply();
+ outSurfaceControl.release();
}
- t.apply();
- outSurfaceControl.copyFrom(sc);
outFrame.set(0, 0, attrs.width, attrs.height);
mergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
@@ -432,7 +432,7 @@
@Override
public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
- IBinder hostInputToken, int flags, InputChannel outInputChannel) {
+ IBinder hostInputToken, int flags, int type, InputChannel outInputChannel) {
}
@Override
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ca5c417..813234f 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -752,7 +752,10 @@
}
}
- private static String typeToString(int type) {
+ /**
+ * @hide
+ */
+ public static String typeToString(int type) {
switch (type) {
case TYPE_APPLICATION: {
return "TYPE_APPLICATION";
@@ -770,7 +773,7 @@
return "TYPE_SPLIT_SCREEN_DIVIDER";
}
default:
- return "<UNKNOWN>";
+ return "<UNKNOWN:" + type + ">";
}
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 1773ec2..553e3c8 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -18,6 +18,7 @@
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
+import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
@@ -879,7 +880,11 @@
* @param view view requesting the new autofill context.
*/
public void requestAutofill(@NonNull View view) {
- notifyViewEntered(view, FLAG_MANUAL_REQUEST);
+ int flags = FLAG_MANUAL_REQUEST;
+ if (!view.isFocused()) {
+ flags |= FLAG_VIEW_NOT_FOCUSED;
+ }
+ notifyViewEntered(view, flags);
}
/**
@@ -926,7 +931,11 @@
* @param absBounds absolute boundaries of the virtual view in the screen.
*/
public void requestAutofill(@NonNull View view, int virtualId, @NonNull Rect absBounds) {
- notifyViewEntered(view, virtualId, absBounds, FLAG_MANUAL_REQUEST);
+ int flags = FLAG_MANUAL_REQUEST;
+ if (!view.isFocused()) {
+ flags |= FLAG_VIEW_NOT_FOCUSED;
+ }
+ notifyViewEntered(view, virtualId, absBounds, flags);
}
/**
@@ -1894,7 +1903,13 @@
final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.addClient(mServiceClient, client.autofillClientGetComponentName(),
userId, receiver);
- final int flags = receiver.getIntResult();
+ int flags = 0;
+ try {
+ flags = receiver.getIntResult();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.w(TAG, "Failed to initialize autofill: " + e);
+ return;
+ }
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 2ead352..3161c3c 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -31,6 +31,7 @@
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.PopupWindow;
+import android.window.WindowMetricsHelper;
/**
* Custom {@link PopupWindow} used to isolate its content from the autofilled app - the
@@ -128,7 +129,8 @@
// Gravity.BOTTOM because PopupWindow base class does not expose computeGravity().
final WindowManager windowManager = anchor.getContext()
.getSystemService(WindowManager.class);
- final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
+ final Rect windowBounds = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ windowManager.getCurrentWindowMetrics());
width = windowBounds.width();
if (height != LayoutParams.MATCH_PARENT) {
offsetY = windowBounds.height() - height;
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 4519aef..d021fc9 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -346,7 +346,7 @@
/** @hide */
- public static final int DEFAULT_MAX_BUFFER_SIZE = 100;
+ public static final int DEFAULT_MAX_BUFFER_SIZE = 500; // Enough for typical busy screen.
/** @hide */
public static final int DEFAULT_IDLE_FLUSHING_FREQUENCY_MS = 5_000;
/** @hide */
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index 6b1a480..e4ac588 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -18,11 +18,13 @@
import android.annotation.BinderThread;
import android.annotation.CallbackExecutor;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
-import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -42,26 +44,26 @@
import java.util.function.Consumer;
/**
- * This class represents an inline suggestion which is made by one app
- * and can be embedded into the UI of another. Suggestions may contain
- * sensitive information not known to the host app which needs to be
- * protected from spoofing. To address that the suggestion view inflated
- * on demand for embedding is created in such a way that the hosting app
- * cannot introspect its content and cannot interact with it.
+ * This class represents an inline suggestion which is made by one app and can be embedded into the
+ * UI of another. Suggestions may contain sensitive information not known to the host app which
+ * needs to be protected from spoofing. To address that the suggestion view inflated on demand for
+ * embedding is created in such a way that the hosting app cannot introspect its content and cannot
+ * interact with it.
*/
-@DataClass(
- genEqualsHashCode = true,
- genToString = true,
- genHiddenConstDefs = true,
+@DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstDefs = true,
genHiddenConstructor = true)
-@DataClass.Suppress({"getContentProvider"})
public final class InlineSuggestion implements Parcelable {
private static final String TAG = "InlineSuggestion";
- private final @NonNull InlineSuggestionInfo mInfo;
+ @NonNull
+ private final InlineSuggestionInfo mInfo;
- private final @Nullable IInlineContentProvider mContentProvider;
+ /**
+ * @hide
+ */
+ @Nullable
+ private final IInlineContentProvider mContentProvider;
/**
* Used to keep a strong reference to the callback so it doesn't get garbage collected.
@@ -69,7 +71,8 @@
* @hide
*/
@DataClass.ParcelWith(InlineContentCallbackImplParceling.class)
- private @Nullable InlineContentCallbackImpl mInlineContentCallback;
+ @Nullable
+ private InlineContentCallbackImpl mInlineContentCallback;
/**
* Creates a new {@link InlineSuggestion}, for testing purpose.
@@ -87,8 +90,7 @@
*
* @hide
*/
- public InlineSuggestion(
- @NonNull InlineSuggestionInfo info,
+ public InlineSuggestion(@NonNull InlineSuggestionInfo info,
@Nullable IInlineContentProvider contentProvider) {
this(info, contentProvider, /* inlineContentCallback */ null);
}
@@ -96,25 +98,30 @@
/**
* Inflates a view with the content of this suggestion at a specific size.
*
- * <p> The size must be either 1) between the
- * {@link android.widget.inline.InlinePresentationSpec#getMinSize() min size} and the
- * {@link android.widget.inline.InlinePresentationSpec#getMaxSize() max size} of the
- * presentation spec returned by {@link InlineSuggestionInfo#getInlinePresentationSpec()},
- * or 2) {@link ViewGroup.LayoutParams#WRAP_CONTENT}. If the size is set to
- * {@link ViewGroup.LayoutParams#WRAP_CONTENT}, then the size of the inflated view will be just
- * large enough to fit the content, while still conforming to the min / max size specified by
- * the {@link android.widget.inline.InlinePresentationSpec}.
+ * <p> Each dimension of the size must satisfy one of the following conditions:
+ *
+ * <ol>
+ * <li>between {@link android.widget.inline.InlinePresentationSpec#getMinSize()} and
+ * {@link android.widget.inline.InlinePresentationSpec#getMaxSize()} of the presentation spec
+ * from {@code mInfo}
+ * <li>{@link ViewGroup.LayoutParams#WRAP_CONTENT}
+ * </ol>
+ *
+ * If the size is set to {@link
+ * ViewGroup.LayoutParams#WRAP_CONTENT}, then the size of the inflated view will be just large
+ * enough to fit the content, while still conforming to the min / max size specified by the
+ * {@link android.widget.inline.InlinePresentationSpec}.
*
* <p> The caller can attach an {@link android.view.View.OnClickListener} and/or an
- * {@link android.view.View.OnLongClickListener} to the view in the
- * {@code callback} to receive click and long click events on the view.
+ * {@link android.view.View.OnLongClickListener} to the view in the {@code callback} to receive
+ * click and long click events on the view.
*
* @param context Context in which to inflate the view.
- * @param size The size at which to inflate the suggestion. For each dimension, it maybe
- * an exact value or {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
- * @param callback Callback for receiving the inflated view, where the
- * {@link ViewGroup.LayoutParams} of the view is set as the actual size of
- * the underlying remote view.
+ * @param size The size at which to inflate the suggestion. For each dimension, it maybe an
+ * exact value or {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
+ * @param callback Callback for receiving the inflated view, where the {@link
+ * ViewGroup.LayoutParams} of the view is set as the actual size of the
+ * underlying remote view.
* @throws IllegalArgumentException If an invalid argument is passed.
* @throws IllegalStateException If this method is already called.
*/
@@ -130,19 +137,17 @@
+ ", nor wrap_content");
}
mInlineContentCallback = getInlineContentCallback(context, callbackExecutor, callback);
- AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
- if (mContentProvider == null) {
- callback.accept(/* view */ null);
- return;
- }
- try {
- mContentProvider.provideContent(size.getWidth(), size.getHeight(),
- new InlineContentCallbackWrapper(mInlineContentCallback));
- } catch (RemoteException e) {
- Slog.w(TAG, "Error creating suggestion content surface: " + e);
- callback.accept(/* view */ null);
- }
- });
+ if (mContentProvider == null) {
+ callbackExecutor.execute(() -> callback.accept(/* view */ null));
+ return;
+ }
+ try {
+ mContentProvider.provideContent(size.getWidth(), size.getHeight(),
+ new InlineContentCallbackWrapper(mInlineContentCallback));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error creating suggestion content surface: " + e);
+ callbackExecutor.execute(() -> callback.accept(/* view */ null));
+ }
}
/**
@@ -161,9 +166,14 @@
if (mInlineContentCallback != null) {
throw new IllegalStateException("Already called #inflate()");
}
- return new InlineContentCallbackImpl(context, callbackExecutor, callback);
+ return new InlineContentCallbackImpl(context, mContentProvider, callbackExecutor,
+ callback);
}
+ /**
+ * A wrapper class around the {@link InlineContentCallbackImpl} to ensure it's not strongly
+ * reference by the remote system server process.
+ */
private static final class InlineContentCallbackWrapper extends IInlineContentCallback.Stub {
private final WeakReference<InlineContentCallbackImpl> mCallbackImpl;
@@ -201,17 +211,68 @@
}
}
+ /**
+ * Handles the communication between the inline suggestion view in current (IME) process and
+ * the remote view provided from the system server.
+ *
+ * <p>This class is thread safe, because all the outside calls are piped into a single
+ * handler thread to be processed.
+ */
private static final class InlineContentCallbackImpl {
- private final @NonNull Context mContext;
- private final @NonNull Executor mCallbackExecutor;
- private final @NonNull Consumer<InlineContentView> mCallback;
- private @Nullable InlineContentView mView;
+ @NonNull
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+ @NonNull
+ private final Context mContext;
+ @Nullable
+ private final IInlineContentProvider mInlineContentProvider;
+ @NonNull
+ private final Executor mCallbackExecutor;
+
+ /**
+ * Callback from the client (IME) that will receive the inflated suggestion view. It'll
+ * only be called once when the view SurfacePackage is first sent back to the client. Any
+ * updates to the view due to attach to window and detach from window events will be
+ * handled under the hood, transparent from the client.
+ */
+ @NonNull
+ private final Consumer<InlineContentView> mCallback;
+
+ /**
+ * Indicates whether the first content has been received or not.
+ */
+ private boolean mFirstContentReceived = false;
+
+ /**
+ * The client (IME) side view which internally wraps a remote view. It'll be set when
+ * {@link #onContent(SurfaceControlViewHost.SurfacePackage, int, int)} is called, which
+ * should only happen once in the lifecycle of this inline suggestion instance.
+ */
+ @Nullable
+ private InlineContentView mView;
+
+ /**
+ * The SurfacePackage pointing to the remote view. It's cached here to be sent to the next
+ * available consumer.
+ */
+ @Nullable
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+
+ /**
+ * The callback (from the {@link InlineContentView}) which consumes the surface package.
+ * It's cached here to be called when the SurfacePackage is returned from the remote
+ * view owning process.
+ */
+ @Nullable
+ private Consumer<SurfaceControlViewHost.SurfacePackage> mSurfacePackageConsumer;
InlineContentCallbackImpl(@NonNull Context context,
+ @Nullable IInlineContentProvider inlineContentProvider,
@NonNull @CallbackExecutor Executor callbackExecutor,
@NonNull Consumer<InlineContentView> callback) {
mContext = context;
+ mInlineContentProvider = inlineContentProvider;
mCallbackExecutor = callbackExecutor;
mCallback = callback;
}
@@ -219,28 +280,112 @@
@BinderThread
public void onContent(SurfaceControlViewHost.SurfacePackage content, int width,
int height) {
- if (content == null) {
+ mMainHandler.post(() -> handleOnContent(content, width, height));
+ }
+
+ @MainThread
+ private void handleOnContent(SurfaceControlViewHost.SurfacePackage content, int width,
+ int height) {
+ if (!mFirstContentReceived) {
+ handleOnFirstContentReceived(content, width, height);
+ mFirstContentReceived = true;
+ } else {
+ handleOnSurfacePackage(content);
+ }
+ }
+
+ /**
+ * Called when the view content is returned for the first time.
+ */
+ @MainThread
+ private void handleOnFirstContentReceived(SurfaceControlViewHost.SurfacePackage content,
+ int width, int height) {
+ mSurfacePackage = content;
+ if (mSurfacePackage == null) {
mCallbackExecutor.execute(() -> mCallback.accept(/* view */null));
} else {
mView = new InlineContentView(mContext);
mView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
- mView.setChildSurfacePackage(content);
+ mView.setChildSurfacePackageUpdater(getSurfacePackageUpdater());
mCallbackExecutor.execute(() -> mCallback.accept(mView));
}
}
+ /**
+ * Called when any subsequent SurfacePackage is returned from the remote view owning
+ * process.
+ */
+ @MainThread
+ private void handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
+ mSurfacePackage = surfacePackage;
+ if (mSurfacePackage != null && mSurfacePackageConsumer != null) {
+ mSurfacePackageConsumer.accept(mSurfacePackage);
+ mSurfacePackageConsumer = null;
+ }
+ }
+
+ @MainThread
+ private void handleOnSurfacePackageReleased() {
+ if (mSurfacePackage != null) {
+ try {
+ mInlineContentProvider.onSurfacePackageReleased();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e);
+ }
+ mSurfacePackage = null;
+ }
+ }
+
+ @MainThread
+ private void handleGetSurfacePackage(
+ Consumer<SurfaceControlViewHost.SurfacePackage> consumer) {
+ if (mSurfacePackage != null) {
+ consumer.accept(mSurfacePackage);
+ } else {
+ mSurfacePackageConsumer = consumer;
+ try {
+ mInlineContentProvider.requestSurfacePackage();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error calling getSurfacePackage(): " + e);
+ consumer.accept(null);
+ mSurfacePackageConsumer = null;
+ }
+ }
+ }
+
+ private InlineContentView.SurfacePackageUpdater getSurfacePackageUpdater() {
+ return new InlineContentView.SurfacePackageUpdater() {
+ @Override
+ public void onSurfacePackageReleased() {
+ mMainHandler.post(
+ () -> InlineContentCallbackImpl.this.handleOnSurfacePackageReleased());
+ }
+
+ @Override
+ public void getSurfacePackage(
+ Consumer<SurfaceControlViewHost.SurfacePackage> consumer) {
+ mMainHandler.post(
+ () -> InlineContentCallbackImpl.this.handleGetSurfacePackage(consumer));
+ }
+ };
+ }
+
@BinderThread
public void onClick() {
- if (mView != null && mView.hasOnClickListeners()) {
- mView.callOnClick();
- }
+ mMainHandler.post(() -> {
+ if (mView != null && mView.hasOnClickListeners()) {
+ mView.callOnClick();
+ }
+ });
}
@BinderThread
public void onLongClick() {
- if (mView != null && mView.hasOnLongClickListeners()) {
- mView.performLongClick();
- }
+ mMainHandler.post(() -> {
+ if (mView != null && mView.hasOnLongClickListeners()) {
+ mView.performLongClick();
+ }
+ });
}
}
@@ -262,6 +407,7 @@
+
// Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
@@ -302,6 +448,14 @@
}
/**
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable IInlineContentProvider getContentProvider() {
+ return mContentProvider;
+ }
+
+ /**
* Used to keep a strong reference to the callback so it doesn't get garbage collected.
*
* @hide
@@ -421,7 +575,7 @@
};
@DataClass.Generated(
- time = 1587771173367L,
+ time = 1589396017700L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
inputSignatures = "private static final java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nprivate static boolean isValid(int,int,int)\nprivate synchronized android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3cf6109..71dd665 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -645,6 +645,11 @@
@Override
public void setCurrentRootView(ViewRootImpl rootView) {
synchronized (mH) {
+ if (mCurRootView != null) {
+ // Reset the last served view and restart window focus state of the root view.
+ mCurRootView.getImeFocusController().setServedView(null);
+ mRestartOnNextWindowFocus = true;
+ }
mCurRootView = rootView;
}
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index f8522ed..f78ec7c 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -189,14 +189,29 @@
public void onCloseWindow(WebView window) {}
/**
- * Tell the client to display a javascript alert dialog. If the client
- * returns {@code true}, WebView will assume that the client will handle the
- * dialog. If the client returns {@code false}, it will continue execution.
+ * Notify the host application that the web page wants to display a
+ * JavaScript {@code alert()} dialog.
+ * <p>The default behavior if this method returns {@code false} or is not
+ * overridden is to show a dialog containing the alert message and suspend
+ * JavaScript execution until the dialog is dismissed.
+ * <p>To show a custom dialog, the app should return {@code true} from this
+ * method, in which case the default dialog will not be shown and JavaScript
+ * execution will be suspended. The app should call
+ * {@code JsResult.confirm()} when the custom dialog is dismissed such that
+ * JavaScript execution can be resumed.
+ * <p>To suppress the dialog and allow JavaScript execution to
+ * continue, call {@code JsResult.confirm()} immediately and then return
+ * {@code true}.
+ * <p>Note that if the {@link WebChromeClient} is {@code null}, the default
+ * dialog will be suppressed and Javascript execution will continue
+ * immediately.
+ *
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
* @param message Message to be displayed in the window.
- * @param result A JsResult to confirm that the user hit enter.
- * @return boolean Whether the client will handle the alert dialog.
+ * @param result A JsResult to confirm that the user closed the window.
+ * @return boolean {@code true} if the request is handled or ignored.
+ * {@code false} if WebView needs to show the default dialog.
*/
public boolean onJsAlert(WebView view, String url, String message,
JsResult result) {
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 35dd576..91b9390 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1118,6 +1118,10 @@
* {@link #setAppCachePath}.
*
* @param flag {@code true} if the WebView should enable Application Caches
+ * @deprecated The Application Cache API is deprecated and this method will
+ * become a no-op on all Android versions once support is
+ * removed in Chromium. Consider using Service Workers instead.
+ * See https://web.dev/appcache-removal/ for more information.
*/
public abstract void setAppCacheEnabled(boolean flag);
@@ -1130,6 +1134,10 @@
* @param appCachePath a String path to the directory containing
* Application Caches files.
* @see #setAppCacheEnabled
+ * @deprecated The Application Cache API is deprecated and this method will
+ * become a no-op on all Android versions once support is
+ * removed in Chromium. Consider using Service Workers instead.
+ * See https://web.dev/appcache-removal/ for more information.
*/
public abstract void setAppCachePath(String appCachePath);
@@ -1142,7 +1150,7 @@
* It is recommended to leave the maximum size set to the default value.
*
* @param appCacheMaxSize the maximum size in bytes
- * @deprecated In future quota will be managed automatically.
+ * @deprecated Quota is managed automatically; this method is a no-op.
*/
@Deprecated
public abstract void setAppCacheMaxSize(long appCacheMaxSize);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 29914aa..226f5797 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8315,23 +8315,6 @@
return false;
}
- /**
- * Returns true if pressing TAB in this field advances focus instead
- * of inserting the character. Insert tabs only in multi-line editors.
- */
- private boolean shouldAdvanceFocusOnTab() {
- if (getKeyListener() != null && !mSingleLine && mEditor != null
- && (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS)
- == EditorInfo.TYPE_CLASS_TEXT) {
- int multilineFlags = EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE
- | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
- if ((mEditor.mInputType & multilineFlags) != 0) {
- return false;
- }
- }
- return true;
- }
-
private boolean isDirectionalNavigationKey(int keyCode) {
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
@@ -8400,9 +8383,8 @@
case KeyEvent.KEYCODE_TAB:
if (event.hasNoModifiers() || event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
- if (shouldAdvanceFocusOnTab()) {
- return KEY_EVENT_NOT_HANDLED;
- }
+ // Tab is used to move focus.
+ return KEY_EVENT_NOT_HANDLED;
}
break;
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 4f2af63..8657e82 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -21,40 +21,45 @@
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
+import java.util.function.Consumer;
+
/**
- * This class represents a view that holds opaque content from another app that
- * you can inline in your UI.
+ * This class represents a view that holds opaque content from another app that you can inline in
+ * your UI.
*
* <p>Since the content presented by this view is from another security domain,it is
- * shown on a remote surface preventing the host application from accessing that content.
- * Also the host application cannot interact with the inlined content by injecting touch
- * events or clicking programmatically.
+ * shown on a remote surface preventing the host application from accessing that content. Also the
+ * host application cannot interact with the inlined content by injecting touch events or clicking
+ * programmatically.
*
* <p>This view can be overlaid by other windows, i.e. redressed, but if this is the case
- * the inined UI would not be interactive. Sometimes this is desirable, e.g. animating
- * transitions.
+ * the inlined UI would not be interactive. Sometimes this is desirable, e.g. animating transitions.
*
* <p>By default the surface backing this view is shown on top of the hosting window such
- * that the inlined content is interactive. However, you can temporarily move the surface
- * under the hosting window which could be useful in some cases, e.g. animating transitions.
- * At this point the inlined content will not be interactive and the touch events would
- * be delivered to your app.
- * <p>
- * Instances of this class are created by the platform and can be programmatically attached
- * to your UI. Once you attach and detach this view it can not longer be reused and you
- * should obtain a new view from the platform via the dedicated APIs.
+ * that the inlined content is interactive. However, you can temporarily move the surface under the
+ * hosting window which could be useful in some cases, e.g. animating transitions. At this point the
+ * inlined content will not be interactive and the touch events would be delivered to your app.
+ *
+ * <p> Instances of this class are created by the platform and can be programmatically attached to
+ * your UI. Once the view is attached to the window, you may detach and reattach it to the window.
+ * It should work seamlessly from the hosting process's point of view.
*/
public class InlineContentView extends ViewGroup {
+ private static final String TAG = "InlineContentView";
+
+ private static final boolean DEBUG = false;
+
/**
- * Callback for observing the lifecycle of the surface control
- * that manipulates the backing secure embedded UI surface.
+ * Callback for observing the lifecycle of the surface control that manipulates the backing
+ * secure embedded UI surface.
*/
public interface SurfaceControlCallback {
/**
@@ -72,15 +77,41 @@
void onDestroyed(@NonNull SurfaceControl surfaceControl);
}
- private final @NonNull SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
+ /**
+ * Callback for sending an updated surface package in case the previous one is released
+ * from the detached from window event, and for getting notified of such event.
+ *
+ * This is expected to be provided to the {@link InlineContentView} so it can get updates
+ * from and send updates to the remote content (i.e. surface package) provider.
+ *
+ * @hide
+ */
+ public interface SurfacePackageUpdater {
+
+ /**
+ * Called when the previous surface package is released due to view being detached
+ * from the window.
+ */
+ void onSurfacePackageReleased();
+
+ /**
+ * Called to request an updated surface package.
+ *
+ * @param consumer consumes the updated surface package.
+ */
+ void getSurfacePackage(Consumer<SurfaceControlViewHost.SurfacePackage> consumer);
+ }
+
+ @NonNull
+ private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
mSurfaceControlCallback.onCreated(mSurfaceView.getSurfaceControl());
}
@Override
- public void surfaceChanged(@NonNull SurfaceHolder holder,
- int format, int width, int height) {
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
/* do nothing */
}
@@ -90,13 +121,17 @@
}
};
- private final @NonNull SurfaceView mSurfaceView;
+ @NonNull
+ private final SurfaceView mSurfaceView;
- private @Nullable SurfaceControlCallback mSurfaceControlCallback;
+ @Nullable
+ private SurfaceControlCallback mSurfaceControlCallback;
+
+ @Nullable
+ private SurfacePackageUpdater mSurfacePackageUpdater;
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context) {
@@ -105,7 +140,6 @@
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -114,7 +148,6 @@
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs,
@@ -123,20 +156,18 @@
}
/**
- * Gets the surface control. If the surface is not created this method
- * returns {@code null}.
+ * Gets the surface control. If the surface is not created this method returns {@code null}.
*
* @return The surface control.
- *
* @see #setSurfaceControlCallback(SurfaceControlCallback)
*/
- public @Nullable SurfaceControl getSurfaceControl() {
+ @Nullable
+ public SurfaceControl getSurfaceControl() {
return mSurfaceView.getSurfaceControl();
}
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs,
@@ -149,14 +180,35 @@
}
/**
- * Sets the embedded UI.
- * @param surfacePackage The embedded UI.
+ * Sets the embedded UI provider.
*
* @hide
*/
- public void setChildSurfacePackage(
- @Nullable SurfaceControlViewHost.SurfacePackage surfacePackage) {
- mSurfaceView.setChildSurfacePackage(surfacePackage);
+ public void setChildSurfacePackageUpdater(
+ @Nullable SurfacePackageUpdater surfacePackageUpdater) {
+ mSurfacePackageUpdater = surfacePackageUpdater;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ if (DEBUG) Log.v(TAG, "onAttachedToWindow");
+ super.onAttachedToWindow();
+ if (mSurfacePackageUpdater != null) {
+ mSurfacePackageUpdater.getSurfacePackage(
+ sp -> {
+ if (DEBUG) Log.v(TAG, "Received new SurfacePackage");
+ mSurfaceView.setChildSurfacePackage(sp);
+ });
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (DEBUG) Log.v(TAG, "onDetachedFromWindow");
+ super.onDetachedFromWindow();
+ if (mSurfacePackageUpdater != null) {
+ mSurfacePackageUpdater.onSurfacePackageReleased();
+ }
}
@Override
@@ -165,8 +217,8 @@
}
/**
- * Sets a callback to observe the lifecycle of the surface control for
- * managing the backing surface.
+ * Sets a callback to observe the lifecycle of the surface control for managing the backing
+ * surface.
*
* @param callback The callback to set or {@code null} to clear.
*/
@@ -182,7 +234,6 @@
/**
* @return Whether the surface backing this view appears on top of its parent.
- *
* @see #setZOrderedOnTop(boolean)
*/
public boolean isZOrderedOnTop() {
@@ -190,17 +241,15 @@
}
/**
- * Controls whether the backing surface is placed on top of this view's window.
- * Normally, it is placed on top of the window, to allow interaction
- * with the inlined UI. Via this method, you can place the surface below the
- * window. This means that all of the contents of the window this view is in
- * will be visible on top of its surface.
+ * Controls whether the backing surface is placed on top of this view's window. Normally, it is
+ * placed on top of the window, to allow interaction with the inlined UI. Via this method, you
+ * can place the surface below the window. This means that all of the contents of the window
+ * this view is in will be visible on top of its surface.
*
* <p> The Z ordering can be changed dynamically if the backing surface is
* created, otherwise the ordering would be applied at surface construction time.
*
* @param onTop Whether to show the surface on top of this view's window.
- *
* @see #isZOrderedOnTop()
*/
public boolean setZOrderedOnTop(boolean onTop) {
diff --git a/core/java/android/window/TaskEmbedder.java b/core/java/android/window/TaskEmbedder.java
index 4257ce0..ca6c568 100644
--- a/core/java/android/window/TaskEmbedder.java
+++ b/core/java/android/window/TaskEmbedder.java
@@ -36,11 +36,14 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.VirtualDisplay;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.view.IWindow;
import android.view.IWindowManager;
+import android.view.IWindowSession;
import android.view.KeyEvent;
import android.view.SurfaceControl;
+import android.view.WindowManagerGlobal;
import dalvik.system.CloseGuard;
@@ -184,31 +187,45 @@
/**
* Called when the task embedder should be initialized.
+ * NOTE: all overriding methods should call this one after they finish their initialization.
* @return whether to report whether the embedder was initialized.
*/
- public abstract boolean onInitialize();
+ public boolean onInitialize() {
+ updateLocationAndTapExcludeRegion();
+ return true;
+ }
/**
* Called when the task embedder should be released.
* @return whether to report whether the embedder was released.
*/
- protected abstract boolean onRelease();
+ protected boolean onRelease() {
+ // Clear tap-exclude region (if any) for this window.
+ clearTapExcludeRegion();
+ return true;
+ }
/**
* Starts presentation of tasks in this container.
*/
- public abstract void start();
+ public void start() {
+ updateLocationAndTapExcludeRegion();
+ }
/**
* Stops presentation of tasks in this container.
*/
- public abstract void stop();
+ public void stop() {
+ clearTapExcludeRegion();
+ }
/**
* This should be called whenever the position or size of the surface changes
* or if touchable areas above the surface are added or removed.
*/
- public abstract void notifyBoundsChanged();
+ public void notifyBoundsChanged() {
+ updateLocationAndTapExcludeRegion();
+ }
/**
* Called to update the dimensions whenever the host size changes.
@@ -268,6 +285,48 @@
}
/**
+ * Updates position and bounds information needed by WM and IME to manage window
+ * focus and touch events properly.
+ * <p>
+ * This should be called whenever the position or size of the surface changes
+ * or if touchable areas above the surface are added or removed.
+ */
+ protected void updateLocationAndTapExcludeRegion() {
+ if (!isInitialized() || mHost.getWindow() == null) {
+ return;
+ }
+ applyTapExcludeRegion(mHost.getWindow(), mHost.getTapExcludeRegion());
+ }
+
+ /**
+ * Call to update the tap exclude region for the window.
+ * <p>
+ * This should not normally be called directly, but through
+ * {@link #updateLocationAndTapExcludeRegion()}. This method
+ * is provided as an optimization when managing multiple TaskSurfaces within a view.
+ *
+ * @see IWindowSession#updateTapExcludeRegion(IWindow, Region)
+ */
+ private void applyTapExcludeRegion(IWindow window, @Nullable Region tapExcludeRegion) {
+ try {
+ IWindowSession session = WindowManagerGlobal.getWindowSession();
+ session.updateTapExcludeRegion(window, tapExcludeRegion);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Removes the tap exclude region set by {@link #updateLocationAndTapExcludeRegion()}.
+ */
+ private void clearTapExcludeRegion() {
+ if (!isInitialized() || mHost.getWindow() == null) {
+ return;
+ }
+ applyTapExcludeRegion(mHost.getWindow(), null);
+ }
+
+ /**
* Set the callback to be notified about state changes.
* <p>This class must finish initializing before {@link #startActivity(Intent)} can be called.
* <p>Note: If the instance was ready prior to this call being made, then
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 2fb4650..1b87521 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -75,7 +75,8 @@
// infrastructure is ready.
mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
- return true;
+
+ return super.onInitialize();
}
@Override
@@ -96,6 +97,7 @@
*/
@Override
public void start() {
+ super.start();
if (DEBUG) {
log("start");
}
@@ -119,6 +121,7 @@
*/
@Override
public void stop() {
+ super.stop();
if (DEBUG) {
log("stop");
}
@@ -143,6 +146,7 @@
*/
@Override
public void notifyBoundsChanged() {
+ super.notifyBoundsChanged();
if (DEBUG) {
log("notifyBoundsChanged: screenBounds=" + mHost.getScreenBounds());
}
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index 6f85dc2..d2614da 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -21,7 +21,6 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
import static android.view.Display.INVALID_DISPLAY;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -40,7 +39,6 @@
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.IWindow;
import android.view.IWindowManager;
import android.view.IWindowSession;
import android.view.InputDevice;
@@ -134,20 +132,15 @@
e.rethrowAsRuntimeException();
}
- if (mHost.getWindow() != null) {
- updateLocationAndTapExcludeRegion();
- }
- return true;
+ return super.onInitialize();
}
@Override
protected boolean onRelease() {
+ super.onRelease();
// Clear activity view geometry for IME on this display
clearActivityViewGeometryForIme();
- // Clear tap-exclude region (if any) for this window.
- clearTapExcludeRegion();
-
if (mTaskStackListener != null) {
try {
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
@@ -170,9 +163,9 @@
*/
@Override
public void start() {
+ super.start();
if (isInitialized()) {
mVirtualDisplay.setDisplayState(true);
- updateLocationAndTapExcludeRegion();
}
}
@@ -181,23 +174,14 @@
*/
@Override
public void stop() {
+ super.stop();
if (isInitialized()) {
mVirtualDisplay.setDisplayState(false);
clearActivityViewGeometryForIme();
- clearTapExcludeRegion();
}
}
/**
- * This should be called whenever the position or size of the surface changes
- * or if touchable areas above the surface are added or removed.
- */
- @Override
- public void notifyBoundsChanged() {
- updateLocationAndTapExcludeRegion();
- }
-
- /**
* Called to update the dimensions whenever the host size changes.
*
* @param width the new width of the surface
@@ -298,12 +282,13 @@
* This should be called whenever the position or size of the surface changes
* or if touchable areas above the surface are added or removed.
*/
- private void updateLocationAndTapExcludeRegion() {
+ @Override
+ protected void updateLocationAndTapExcludeRegion() {
+ super.updateLocationAndTapExcludeRegion();
if (!isInitialized() || mHost.getWindow() == null) {
return;
}
reportLocation(mHost.getScreenToTaskMatrix(), mHost.getPositionInWindow());
- applyTapExcludeRegion(mHost.getWindow(), mHost.getTapExcludeRegion());
}
/**
@@ -332,24 +317,6 @@
}
/**
- * Call to update the tap exclude region for the window.
- * <p>
- * This should not normally be called directly, but through
- * {@link #updateLocationAndTapExcludeRegion()}. This method
- * is provided as an optimization when managing multiple TaskSurfaces within a view.
- *
- * @see IWindowSession#updateTapExcludeRegion(IWindow, Region)
- */
- private void applyTapExcludeRegion(IWindow window, @Nullable Region tapExcludeRegion) {
- try {
- IWindowSession session = WindowManagerGlobal.getWindowSession();
- session.updateTapExcludeRegion(window, tapExcludeRegion);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- }
-
- /**
* @see InputMethodManager#reportActivityView(int, Matrix)
*/
private void clearActivityViewGeometryForIme() {
@@ -357,17 +324,6 @@
mContext.getSystemService(InputMethodManager.class).reportActivityView(displayId, null);
}
- /**
- * Removes the tap exclude region set by {@link #updateLocationAndTapExcludeRegion()}.
- */
- private void clearTapExcludeRegion() {
- if (mHost.getWindow() == null) {
- Log.w(TAG, "clearTapExcludeRegion: not attached to window!");
- return;
- }
- applyTapExcludeRegion(mHost.getWindow(), null);
- }
-
private static KeyEvent createKeyEvent(int action, int code, int displayId) {
long when = SystemClock.uptimeMillis();
final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
@@ -380,11 +336,7 @@
/** Get density of the hosting display. */
private int getBaseDisplayDensity() {
- if (mTmpDisplayMetrics == null) {
- mTmpDisplayMetrics = new DisplayMetrics();
- }
- mContext.getDisplayNoVerify().getRealMetrics(mTmpDisplayMetrics);
- return mTmpDisplayMetrics.densityDpi;
+ return mContext.getResources().getConfiguration().densityDpi;
}
/**
diff --git a/core/java/android/window/WindowMetricsHelper.java b/core/java/android/window/WindowMetricsHelper.java
new file mode 100644
index 0000000..fb8b27e
--- /dev/null
+++ b/core/java/android/window/WindowMetricsHelper.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.WindowInsets.Type.displayCutout;
+import static android.view.WindowInsets.Type.navigationBars;
+
+import android.annotation.NonNull;
+import android.graphics.Insets;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.ViewRootImpl;
+import android.view.WindowInsets;
+import android.view.WindowMetrics;
+
+/**
+ * Helper class to calculate size with {@link android.graphics.Insets} based on provided
+ * {@link WindowMetrics}
+ *
+ * @hide
+ */
+public final class WindowMetricsHelper {
+ private WindowMetricsHelper() {}
+
+ /**
+ * Returns bounds excluding navigation bar and display cutout (but including status bar).
+ * This has the same behavior as {@link Display#getSize(Point)}.
+ */
+ public static Rect getBoundsExcludingNavigationBarAndCutout(
+ @NonNull WindowMetrics windowMetrics) {
+ final WindowInsets windowInsets = windowMetrics.getWindowInsets();
+ Insets insets;
+ if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+ insets = windowInsets.getInsetsIgnoringVisibility(navigationBars() | displayCutout());
+ } else {
+ final Insets stableInsets = windowInsets.getStableInsets();
+ insets = Insets.of(stableInsets.left, 0 /* top */, stableInsets.right,
+ stableInsets.bottom);
+ final DisplayCutout cutout = windowInsets.getDisplayCutout();
+ insets = (cutout != null) ? Insets.max(insets, Insets.of(cutout.getSafeInsets()))
+ : insets;
+ }
+ final Rect result = new Rect(windowMetrics.getBounds());
+ result.inset(insets);
+ return result;
+ }
+}
diff --git a/core/java/com/android/internal/BrightnessSynchronizer.java b/core/java/com/android/internal/BrightnessSynchronizer.java
index aa23251..42724be 100644
--- a/core/java/com/android/internal/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/BrightnessSynchronizer.java
@@ -84,17 +84,17 @@
* Converts between the int brightness system and the float brightness system.
*/
public static float brightnessIntToFloat(Context context, int brightnessInt) {
- PowerManager pm = context.getSystemService(PowerManager.class);
- float pmMinBrightness = pm.getBrightnessConstraint(
+ final PowerManager pm = context.getSystemService(PowerManager.class);
+ final float pmMinBrightness = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
- float pmMaxBrightness = pm.getBrightnessConstraint(
+ final float pmMaxBrightness = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
- int minBrightnessInt = brightnessFloatToInt(pmMinBrightness, PowerManager.BRIGHTNESS_MIN,
- PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_OFF + 1,
- PowerManager.BRIGHTNESS_ON);
- int maxBrightnessInt = brightnessFloatToInt(pmMaxBrightness, PowerManager.BRIGHTNESS_MIN,
- PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_OFF + 1,
- PowerManager.BRIGHTNESS_ON);
+ final int minBrightnessInt = Math.round(brightnessFloatToIntRange(pmMinBrightness,
+ PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX,
+ PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON));
+ final int maxBrightnessInt = Math.round(brightnessFloatToIntRange(pmMaxBrightness,
+ PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX,
+ PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON));
return brightnessIntToFloat(brightnessInt, minBrightnessInt, maxBrightnessInt,
pmMinBrightness, pmMaxBrightness);
@@ -119,34 +119,43 @@
* Converts between the float brightness system and the int brightness system.
*/
public static int brightnessFloatToInt(Context context, float brightnessFloat) {
- PowerManager pm = context.getSystemService(PowerManager.class);
- float pmMinBrightness = pm.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
- float pmMaxBrightness = pm.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
- int minBrightnessInt = brightnessFloatToInt(pmMinBrightness, PowerManager.BRIGHTNESS_MIN,
- PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_OFF + 1,
- PowerManager.BRIGHTNESS_ON);
- int maxBrightnessInt = brightnessFloatToInt(pmMaxBrightness, PowerManager.BRIGHTNESS_MIN,
- PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_OFF + 1,
- PowerManager.BRIGHTNESS_ON);
-
- return brightnessFloatToInt(brightnessFloat, pmMinBrightness, pmMaxBrightness,
- minBrightnessInt, maxBrightnessInt);
+ return Math.round(brightnessFloatToIntRange(context, brightnessFloat));
}
/**
- * Converts between the float brightness system and the int brightness system.
+ * Converts between the float brightness system and the int brightness system, but returns
+ * the converted value as a float within the int-system's range. This method helps with
+ * conversions from one system to the other without losing the floating-point precision.
*/
- public static int brightnessFloatToInt(float brightnessFloat, float minFloat, float maxFloat,
- int minInt, int maxInt) {
+ public static float brightnessFloatToIntRange(Context context, float brightnessFloat) {
+ final PowerManager pm = context.getSystemService(PowerManager.class);
+ final float minFloat = pm.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
+ final float maxFloat = pm.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
+ final float minInt = brightnessFloatToIntRange(minFloat,
+ PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX,
+ PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON);
+ final float maxInt = brightnessFloatToIntRange(maxFloat,
+ PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX,
+ PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON);
+ return brightnessFloatToIntRange(brightnessFloat, minFloat, maxFloat, minInt, maxInt);
+ }
+
+ /**
+ * Translates specified value from the float brightness system to the int brightness system,
+ * given the min/max of each range. Accounts for special values such as OFF and invalid values.
+ * Value returned as a float privimite (to preserve precision), but is a value within the
+ * int-system range.
+ */
+ private static float brightnessFloatToIntRange(float brightnessFloat, float minFloat,
+ float maxFloat, float minInt, float maxInt) {
if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) {
return PowerManager.BRIGHTNESS_OFF;
} else if (Float.isNaN(brightnessFloat)) {
return PowerManager.BRIGHTNESS_INVALID;
} else {
- return Math.round(MathUtils.constrainedMap((float) minInt, (float) maxInt, minFloat,
- maxFloat, brightnessFloat));
+ return MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat, brightnessFloat);
}
}
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index be66d0c..a3c29a8 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
+import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.internal.util.ArrayUtils.convertToLongArray;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -52,6 +53,7 @@
import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.annotation.Retention;
@@ -73,8 +75,11 @@
new ComponentName("com.android.server.accessibility", "ColorInversion");
public static final ComponentName DALTONIZER_COMPONENT_NAME =
new ComponentName("com.android.server.accessibility", "Daltonizer");
+ // TODO(b/147990389): Use MAGNIFICATION_COMPONENT_NAME to replace.
public static final String MAGNIFICATION_CONTROLLER_NAME =
"com.android.server.accessibility.MagnificationController";
+ public static final ComponentName MAGNIFICATION_COMPONENT_NAME =
+ new ComponentName("com.android.server.accessibility", "Magnification");
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -264,16 +269,21 @@
}
private AlertDialog createShortcutWarningDialog(int userId) {
- final String warningMessage = mContext.getString(
- R.string.accessibility_shortcut_toogle_warning);
+ List<AccessibilityTarget> targets = getTargets(mContext, ACCESSIBILITY_SHORTCUT_KEY);
+ if (targets.size() == 0) {
+ return null;
+ }
+
+ // Avoid non-a11y users accidentally turning shortcut on without reading this carefully.
+ // Put "don't turn on" as the primary action.
final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(
// Use SystemUI context so we pick up any theme set in a vendor overlay
mFrameworkObjectProvider.getSystemUiContext())
- .setTitle(R.string.accessibility_shortcut_warning_dialog_title)
- .setMessage(warningMessage)
+ .setTitle(getShortcutWarningTitle(targets))
+ .setMessage(getShortcutWarningMessage(targets))
.setCancelable(false)
- .setPositiveButton(R.string.leave_accessibility_shortcut_on, null)
- .setNegativeButton(R.string.disable_accessibility_shortcut,
+ .setNegativeButton(R.string.accessibility_shortcut_on, null)
+ .setPositiveButton(R.string.accessibility_shortcut_off,
(DialogInterface d, int which) -> {
Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "",
@@ -294,6 +304,32 @@
return alertDialog;
}
+ private String getShortcutWarningTitle(List<AccessibilityTarget> targets) {
+ if (targets.size() == 1) {
+ return mContext.getString(
+ R.string.accessibility_shortcut_single_service_warning_title,
+ targets.get(0).getLabel());
+ }
+ return mContext.getString(
+ R.string.accessibility_shortcut_multiple_service_warning_title);
+ }
+
+ private String getShortcutWarningMessage(List<AccessibilityTarget> targets) {
+ if (targets.size() == 1) {
+ return mContext.getString(
+ R.string.accessibility_shortcut_single_service_warning,
+ targets.get(0).getLabel());
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ for (AccessibilityTarget target : targets) {
+ sb.append(mContext.getString(R.string.accessibility_shortcut_multiple_service_list,
+ target.getLabel()));
+ }
+ return mContext.getString(R.string.accessibility_shortcut_multiple_service_warning,
+ sb.toString());
+ }
+
private AccessibilityServiceInfo getInfoForTargetService() {
final ComponentName targetComponentName = getShortcutTargetComponentName();
if (targetComponentName == null) {
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
index 7c4df52..7eb09e5 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
@@ -19,10 +19,14 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
+import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityButtonLongPressStatus;
import android.annotation.Nullable;
import android.app.Activity;
+import android.content.ComponentName;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -87,6 +91,12 @@
gridview.setAdapter(new ButtonTargetAdapter(mTargets));
gridview.setOnItemClickListener((parent, view, position, id) -> {
final String key = Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT;
+ String name = mTargets.get(position).getId();
+ if (name.equals(MAGNIFICATION_CONTROLLER_NAME)) {
+ name = MAGNIFICATION_COMPONENT_NAME.flattenToString();
+ }
+ final ComponentName componentName = ComponentName.unflattenFromString(name);
+ logAccessibilityButtonLongPressStatus(componentName);
Settings.Secure.putString(getContentResolver(), key, mTargets.get(position).getId());
finish();
});
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
index 37871d0..d756593 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
@@ -38,7 +38,7 @@
* Abstract base class for creating various target related to accessibility service,
* accessibility activity, and white listing feature.
*/
-abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener,
+public abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener,
OnTargetCheckedChangeListener {
private Context mContext;
@ShortcutType
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index f63cbe0..60a102a 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -53,19 +53,61 @@
/**
* Collection of utilities for accessibility target.
*/
-final class AccessibilityTargetHelper {
+public final class AccessibilityTargetHelper {
private AccessibilityTargetHelper() {}
- static List<AccessibilityTarget> getTargets(Context context,
+ /**
+ * Returns list of {@link AccessibilityTarget} of assigned accessibility shortcuts from
+ * {@link AccessibilityManager#getAccessibilityShortcutTargets} including accessibility
+ * feature's package name, component id, etc.
+ *
+ * @param context The context of the application.
+ * @param shortcutType The shortcut type.
+ * @return The list of {@link AccessibilityTarget}.
+ * @hide
+ */
+ public static List<AccessibilityTarget> getTargets(Context context,
@ShortcutType int shortcutType) {
- final List<AccessibilityTarget> targets = getInstalledTargets(context, shortcutType);
- final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
- final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(shortcutType);
- targets.removeIf(target -> !requiredTargets.contains(target.getId()));
+ // List all accessibility target
+ final List<AccessibilityTarget> installedTargets = getInstalledTargets(context,
+ shortcutType);
- return targets;
+ // List accessibility shortcut target
+ final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+ final List<String> assignedTargets = am.getAccessibilityShortcutTargets(shortcutType);
+
+ // Get the list of accessibility shortcut target in all accessibility target
+ final List<AccessibilityTarget> results = new ArrayList<>();
+ for (String assignedTarget : assignedTargets) {
+ for (AccessibilityTarget installedTarget : installedTargets) {
+ if (!MAGNIFICATION_CONTROLLER_NAME.contentEquals(assignedTarget)) {
+ final ComponentName assignedTargetComponentName =
+ ComponentName.unflattenFromString(assignedTarget);
+ final ComponentName targetComponentName = ComponentName.unflattenFromString(
+ installedTarget.getId());
+ if (assignedTargetComponentName.equals(targetComponentName)) {
+ results.add(installedTarget);
+ continue;
+ }
+ }
+ if (assignedTarget.contentEquals(installedTarget.getId())) {
+ results.add(installedTarget);
+ }
+ }
+ }
+ return results;
}
+ /**
+ * Returns list of {@link AccessibilityTarget} of the installed accessibility service,
+ * accessibility activity, and white listing feature including accessibility feature's package
+ * name, component id, etc.
+ *
+ * @param context The context of the application.
+ * @param shortcutType The shortcut type.
+ * @return The list of {@link AccessibilityTarget}.
+ */
static List<AccessibilityTarget> getInstalledTargets(Context context,
@ShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
@@ -110,9 +152,10 @@
private static List<AccessibilityTarget> getAccessibilityServiceTargets(Context context,
@ShortcutType int shortcutType) {
- final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
+ final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
final List<AccessibilityServiceInfo> installedServices =
- ams.getInstalledAccessibilityServiceList();
+ am.getInstalledAccessibilityServiceList();
if (installedServices == null) {
return Collections.emptyList();
}
@@ -136,9 +179,10 @@
private static List<AccessibilityTarget> getAccessibilityActivityTargets(Context context,
@ShortcutType int shortcutType) {
- final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
+ final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
final List<AccessibilityShortcutInfo> installedServices =
- ams.getInstalledAccessibilityShortcutListAsUser(context,
+ am.getInstalledAccessibilityShortcutListAsUser(context,
ActivityManager.getCurrentUser());
if (installedServices == null) {
return Collections.emptyList();
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
new file mode 100644
index 0000000..c2e1426
--- /dev/null
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -0,0 +1,130 @@
+/*
+ * 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.internal.accessibility.util;
+
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
+
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__DISABLED;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__ENABLED;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
+
+import android.content.ComponentName;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityManager.ShortcutType;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+/** Methods for logging accessibility states. */
+public final class AccessibilityStatsLogUtils {
+ private static final int UNKNOWN_STATUS =
+ ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__UNKNOWN;
+
+ private AccessibilityStatsLogUtils() {}
+
+ /**
+ * Logs accessibility feature name that is assigned to the shortcut also its shortcut type.
+ * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON} or
+ * {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}
+ *
+ * @param componentName component name of the accessibility feature
+ * @param shortcutType accessibility shortcut type {@link ShortcutType}
+ */
+ public static void logAccessibilityShortcutActivated(ComponentName componentName,
+ @ShortcutType int shortcutType) {
+ logAccessibilityShortcutActivated(componentName, shortcutType, UNKNOWN_STATUS);
+ }
+
+ /**
+ * Logs accessibility feature name that is assigned to the shortcut also its shortcut type and
+ * enabled status. Calls this when clicking the shortcut
+ * {@link AccessibilityManager#ACCESSIBILITY_BUTTON}
+ * or {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}
+ *
+ * @param componentName component name of the accessibility feature
+ * @param shortcutType accessibility shortcut type
+ * @param serviceEnabled {@code true} if the service is enabled
+ */
+ public static void logAccessibilityShortcutActivated(ComponentName componentName,
+ @ShortcutType int shortcutType, boolean serviceEnabled) {
+ logAccessibilityShortcutActivated(componentName, shortcutType,
+ convertToLoggingServiceStatus(serviceEnabled));
+ }
+
+ /**
+ * Logs accessibility feature name that is assigned to the shortcut also its shortcut type and
+ * status code. Calls this when clicking the shortcut
+ * {@link AccessibilityManager#ACCESSIBILITY_BUTTON}
+ * or {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}
+ *
+ * @param componentName component name of the accessibility feature
+ * @param shortcutType accessibility shortcut type {@link ShortcutType}
+ * @param serviceStatus The service status code. 0 denotes unknown_status, 1 denotes enabled, 2
+ * denotes disabled.
+ */
+ private static void logAccessibilityShortcutActivated(ComponentName componentName,
+ @ShortcutType int shortcutType, int serviceStatus) {
+ FrameworkStatsLog.write(FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED,
+ componentName.flattenToString(), convertToLoggingShortcutType(shortcutType),
+ serviceStatus);
+ }
+
+ /**
+ * Logs magnification that is assigned to the triple tap shortcut. Calls this when triggering
+ * the magnification triple tap shortcut.
+ */
+ public static void logMagnificationTripleTap(boolean enabled) {
+ FrameworkStatsLog.write(FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED,
+ MAGNIFICATION_COMPONENT_NAME.flattenToString(),
+ ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP,
+ convertToLoggingServiceStatus(enabled));
+ }
+
+ /**
+ * Logs accessibility feature name that is assigned to the long pressed accessibility button
+ * shortcut. Calls this when clicking the long pressed accessibility button shortcut.
+ *
+ * @param componentName The component name of the accessibility feature.
+ */
+ public static void logAccessibilityButtonLongPressStatus(ComponentName componentName) {
+ FrameworkStatsLog.write(FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED,
+ componentName.flattenToString(),
+ ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS,
+ UNKNOWN_STATUS);
+ }
+
+ private static int convertToLoggingShortcutType(@ShortcutType int shortcutType) {
+ switch (shortcutType) {
+ case ACCESSIBILITY_BUTTON:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ case ACCESSIBILITY_SHORTCUT_KEY:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
+ }
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
+ }
+
+ private static int convertToLoggingServiceStatus(boolean enabled) {
+ return enabled ? ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__ENABLED
+ : ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__DISABLED;
+ }
+}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index e50b010..9ee0b0e 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -142,7 +142,8 @@
*/
public static boolean isAccessibilityServiceEnabled(Context context,
@NonNull String componentId) {
- final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
+ final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
final List<AccessibilityServiceInfo> enabledServices =
am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 100422f..31ccb6c3 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -137,7 +137,8 @@
*/
public static boolean isShortcutContained(Context context, @ShortcutType int shortcutType,
@NonNull String componentId) {
- final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
+ final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
final List<String> requiredTargets = am.getAccessibilityShortcutTargets(shortcutType);
return requiredTargets.contains(componentId);
}
diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
index 37a5a63..0d16cc4 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -128,9 +128,8 @@
mResolverRankerService.compute(targets);
} else {
Log.i(TAG, "AppPredictionService response received");
- Message msg =
- Message.obtain(mHandler, RANKER_SERVICE_RESULT, sortedAppTargets);
- msg.sendToTarget();
+ // Skip sending to Handler which takes extra time to dispatch messages.
+ handleResult(sortedAppTargets);
}
}
);
@@ -141,23 +140,35 @@
// Null value is okay if we have defaulted to the ResolverRankerService.
if (msg.what == RANKER_SERVICE_RESULT && msg.obj != null) {
final List<AppTarget> sortedAppTargets = (List<AppTarget>) msg.obj;
- if (checkAppTargetRankValid(sortedAppTargets)) {
- sortedAppTargets.forEach(target -> mTargetScores.put(
- new ComponentName(target.getPackageName(), target.getClassName()),
- target.getRank()));
- }
- for (int i = 0; i < sortedAppTargets.size(); i++) {
- ComponentName componentName = new ComponentName(
- sortedAppTargets.get(i).getPackageName(),
- sortedAppTargets.get(i).getClassName());
- mTargetRanks.put(componentName, i);
- Log.i(TAG, "handleResultMessage, sortedAppTargets #" + i + ": " + componentName);
- }
+ handleSortedAppTargets(sortedAppTargets);
} else if (msg.obj == null && mResolverRankerService == null) {
Log.e(TAG, "Unexpected null result");
}
}
+ private void handleResult(List<AppTarget> sortedAppTargets) {
+ if (mHandler.hasMessages(RANKER_RESULT_TIMEOUT)) {
+ handleSortedAppTargets(sortedAppTargets);
+ mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
+ afterCompute();
+ }
+ }
+
+ private void handleSortedAppTargets(List<AppTarget> sortedAppTargets) {
+ if (checkAppTargetRankValid(sortedAppTargets)) {
+ sortedAppTargets.forEach(target -> mTargetScores.put(
+ new ComponentName(target.getPackageName(), target.getClassName()),
+ target.getRank()));
+ }
+ for (int i = 0; i < sortedAppTargets.size(); i++) {
+ ComponentName componentName = new ComponentName(
+ sortedAppTargets.get(i).getPackageName(),
+ sortedAppTargets.get(i).getClassName());
+ mTargetRanks.put(componentName, i);
+ Log.i(TAG, "handleSortedAppTargets, sortedAppTargets #" + i + ": " + componentName);
+ }
+ }
+
private boolean checkAppTargetRankValid(List<AppTarget> sortedAppTargets) {
for (AppTarget target : sortedAppTargets) {
if (target.getRank() != 0) {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index be06913..9950e55 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -158,6 +158,7 @@
private static final String TAG = "ChooserActivity";
private AppPredictor mPersonalAppPredictor;
private AppPredictor mWorkAppPredictor;
+ private boolean mShouldDisplayLandscape;
@UnsupportedAppUsage
public ChooserActivity() {
@@ -253,7 +254,7 @@
private boolean mChooserTargetRankingEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.CHOOSER_TARGET_RANKING_ENABLED,
- false);
+ true);
private Bundle mReplacementExtras;
private IntentSender mChosenComponentSender;
@@ -716,6 +717,8 @@
mCallerChooserTargets = targets;
}
+ mShouldDisplayLandscape = shouldDisplayLandscape(
+ getResources().getConfiguration().orientation);
setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false));
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
@@ -775,6 +778,11 @@
mDirectShareShortcutInfoCache = new HashMap<>();
}
+ @Override
+ protected int appliedThemeResId() {
+ return R.style.Theme_DeviceDefault_Chooser;
+ }
+
private AppPredictor setupAppPredictorForUser(UserHandle userHandle,
AppPredictor.Callback appPredictorCallback) {
AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(userHandle);
@@ -884,7 +892,8 @@
/* context */ this,
adapter,
getPersonalProfileUserHandle(),
- /* workProfileUserHandle= */ null);
+ /* workProfileUserHandle= */ null,
+ isSendAction(getTargetIntent()));
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
@@ -914,7 +923,8 @@
workAdapter,
selectedProfile,
getPersonalProfileUserHandle(),
- getWorkProfileUserHandle());
+ getWorkProfileUserHandle(),
+ isSendAction(getTargetIntent()));
}
private int findSelectedProfile() {
@@ -1071,6 +1081,7 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mShouldDisplayLandscape = shouldDisplayLandscape(newConfig.orientation);
adjustPreviewWidth(newConfig.orientation, null);
updateStickyContentPreview();
}
@@ -1084,7 +1095,7 @@
private void adjustPreviewWidth(int orientation, View parent) {
int width = -1;
- if (shouldDisplayLandscape(orientation)) {
+ if (mShouldDisplayLandscape) {
width = getResources().getDimensionPixelSize(R.dimen.chooser_preview_width);
}
@@ -2938,6 +2949,19 @@
.setSubtype(previewType));
}
+ class ViewHolderBase extends RecyclerView.ViewHolder {
+ private int mViewType;
+
+ ViewHolderBase(View itemView, int viewType) {
+ super(itemView);
+ this.mViewType = viewType;
+ }
+
+ int getViewType() {
+ return mViewType;
+ }
+ }
+
/**
* Used to bind types of individual item including
* {@link ChooserGridAdapter#VIEW_TYPE_NORMAL},
@@ -2945,12 +2969,12 @@
* {@link ChooserGridAdapter#VIEW_TYPE_PROFILE},
* and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}.
*/
- final class ItemViewHolder extends RecyclerView.ViewHolder {
+ final class ItemViewHolder extends ViewHolderBase {
ResolverListAdapter.ViewHolder mWrappedViewHolder;
int mListPosition = ChooserListAdapter.NO_POSITION;
- ItemViewHolder(View itemView, boolean isClickable) {
- super(itemView);
+ ItemViewHolder(View itemView, boolean isClickable, int viewType) {
+ super(itemView, viewType);
mWrappedViewHolder = new ResolverListAdapter.ViewHolder(itemView);
if (isClickable) {
itemView.setOnClickListener(v -> startSelected(mListPosition,
@@ -2968,9 +2992,9 @@
/**
* Add a footer to the list, to support scrolling behavior below the navbar.
*/
- final class FooterViewHolder extends RecyclerView.ViewHolder {
- FooterViewHolder(View itemView) {
- super(itemView);
+ final class FooterViewHolder extends ViewHolderBase {
+ FooterViewHolder(View itemView, int viewType) {
+ super(itemView, viewType);
}
}
@@ -3081,7 +3105,7 @@
int getMaxTargetsPerRow() {
int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
- if (shouldDisplayLandscape(getResources().getConfiguration().orientation)) {
+ if (mShouldDisplayLandscape) {
maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
}
return maxTargets;
@@ -3189,13 +3213,14 @@
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_CONTENT_PREVIEW:
- return new ItemViewHolder(createContentPreviewView(parent), false);
+ return new ItemViewHolder(createContentPreviewView(parent), false, viewType);
case VIEW_TYPE_PROFILE:
- return new ItemViewHolder(createProfileView(parent), false);
+ return new ItemViewHolder(createProfileView(parent), false, viewType);
case VIEW_TYPE_AZ_LABEL:
- return new ItemViewHolder(createAzLabelView(parent), false);
+ return new ItemViewHolder(createAzLabelView(parent), false, viewType);
case VIEW_TYPE_NORMAL:
- return new ItemViewHolder(mChooserListAdapter.createView(parent), true);
+ return new ItemViewHolder(
+ mChooserListAdapter.createView(parent), true, viewType);
case VIEW_TYPE_DIRECT_SHARE:
case VIEW_TYPE_CALLER_AND_RANK:
return createItemGroupViewHolder(viewType, parent);
@@ -3203,7 +3228,7 @@
Space sp = new Space(parent.getContext());
sp.setLayoutParams(new RecyclerView.LayoutParams(
LayoutParams.MATCH_PARENT, mFooterHeight));
- return new FooterViewHolder(sp);
+ return new FooterViewHolder(sp, viewType);
default:
// Since we catch all possible viewTypes above, no chance this is being called.
return null;
@@ -3212,7 +3237,7 @@
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- int viewType = getItemViewType(position);
+ int viewType = ((ViewHolderBase) holder).getViewType();
switch (viewType) {
case VIEW_TYPE_DIRECT_SHARE:
case VIEW_TYPE_CALLER_AND_RANK:
@@ -3323,7 +3348,6 @@
}
viewGroup.setTag(holder);
-
return holder;
}
@@ -3350,14 +3374,15 @@
parentGroup.addView(row2);
mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
- Lists.newArrayList(row1, row2), getMaxTargetsPerRow());
+ Lists.newArrayList(row1, row2), getMaxTargetsPerRow(), viewType);
loadViewsIntoGroup(mDirectShareViewHolder);
return mDirectShareViewHolder;
} else {
ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent,
false);
- ItemGroupViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow());
+ ItemGroupViewHolder holder =
+ new SingleRowViewHolder(row, getMaxTargetsPerRow(), viewType);
loadViewsIntoGroup(holder);
return holder;
@@ -3481,13 +3506,11 @@
}
/**
- * Only expand direct share area if there is a minimum number of shortcuts,
- * which will help reduce the amount of visible shuffling due to older-style
- * direct share targets.
+ * Only expand direct share area if there is a minimum number of targets.
*/
private boolean canExpandDirectShare() {
int orientation = getResources().getConfiguration().orientation;
- return mChooserListAdapter.getNumShortcutResults() > getMaxTargetsPerRow()
+ return mChooserListAdapter.getNumServiceTargetsForExpand() > getMaxTargetsPerRow()
&& orientation == Configuration.ORIENTATION_PORTRAIT
&& !isInMultiWindowMode();
}
@@ -3519,14 +3542,14 @@
* {@link ChooserGridAdapter#VIEW_TYPE_DIRECT_SHARE},
* and {@link ChooserGridAdapter#VIEW_TYPE_CALLER_AND_RANK}.
*/
- abstract class ItemGroupViewHolder extends RecyclerView.ViewHolder {
+ abstract class ItemGroupViewHolder extends ViewHolderBase {
protected int mMeasuredRowHeight;
private int[] mItemIndices;
protected final View[] mCells;
private final int mColumnCount;
- ItemGroupViewHolder(int cellCount, View itemView) {
- super(itemView);
+ ItemGroupViewHolder(int cellCount, View itemView, int viewType) {
+ super(itemView, viewType);
this.mCells = new View[cellCount];
this.mItemIndices = new int[cellCount];
this.mColumnCount = cellCount;
@@ -3572,8 +3595,8 @@
class SingleRowViewHolder extends ItemGroupViewHolder {
private final ViewGroup mRow;
- SingleRowViewHolder(ViewGroup row, int cellCount) {
- super(cellCount, row);
+ SingleRowViewHolder(ViewGroup row, int cellCount, int viewType) {
+ super(cellCount, row, viewType);
this.mRow = row;
}
@@ -3615,8 +3638,9 @@
private final boolean[] mCellVisibility;
- DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) {
- super(rows.size() * cellCountPerRow, parent);
+ DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow,
+ int viewType) {
+ super(rows.size() * cellCountPerRow, parent, viewType);
this.mParent = parent;
this.mRows = rows;
@@ -3695,8 +3719,12 @@
// only expand if we have more than maxTargetsPerRow, and delay that decision
// until they start to scroll
- if (mChooserMultiProfilePagerAdapter.getActiveListAdapter()
- .getSelectableServiceTargetCount() <= maxTargetsPerRow) {
+ ChooserListAdapter adapter =
+ mChooserMultiProfilePagerAdapter.getActiveListAdapter();
+ int validTargets =
+ mAppendDirectShareEnabled ? adapter.getNumServiceTargetsForExpand()
+ : adapter.getSelectableServiceTargetCount();
+ if (validTargets <= maxTargetsPerRow) {
mHideDirectShareExpansion = true;
return;
}
diff --git a/core/java/com/android/internal/app/ChooserGridLayoutManager.java b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
new file mode 100644
index 0000000..317a987
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
@@ -0,0 +1,70 @@
+/*
+ * 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.internal.app;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.internal.widget.GridLayoutManager;
+import com.android.internal.widget.RecyclerView;
+
+/**
+ * For a11y and per {@link RecyclerView#onInitializeAccessibilityNodeInfo}, override
+ * methods to ensure proper row counts.
+ */
+public class ChooserGridLayoutManager extends GridLayoutManager {
+
+ /**
+ * Constructor used when layout manager is set in XML by RecyclerView attribute
+ * "layoutManager". If spanCount is not specified in the XML, it defaults to a
+ * single column.
+ *
+ */
+ public ChooserGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ /**
+ * Creates a vertical GridLayoutManager
+ *
+ * @param context Current context, will be used to access resources.
+ * @param spanCount The number of columns in the grid
+ */
+ public ChooserGridLayoutManager(Context context, int spanCount) {
+ super(context, spanCount);
+ }
+
+ /**
+ * @param context Current context, will be used to access resources.
+ * @param spanCount The number of columns or rows in the grid
+ * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link
+ * #VERTICAL}.
+ * @param reverseLayout When set to true, layouts from end to start.
+ */
+ public ChooserGridLayoutManager(Context context, int spanCount, int orientation,
+ boolean reverseLayout) {
+ super(context, spanCount, orientation, reverseLayout);
+ }
+
+ @Override
+ public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ // Do not count the footer view in the official count
+ return super.getRowCountForAccessibility(recycler, state) - 1;
+ }
+}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index f426bc0..f1b7161 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.UserHandle;
import android.os.UserManager;
@@ -78,6 +79,7 @@
private static final int MAX_SUGGESTED_APP_TARGETS = 4;
private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
+ private static final int MAX_SERVICE_TARGET_APP = 8;
static final int MAX_SERVICE_TARGETS = 8;
@@ -97,13 +99,14 @@
private ChooserTargetInfo
mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo();
private int mValidServiceTargetsNum = 0;
+ private int mAvailableServiceTargetsNum = 0;
private final Map<ComponentName, Pair<List<ChooserTargetInfo>, Integer>>
mParkingDirectShareTargets = new HashMap<>();
private final Map<ComponentName, Map<String, Integer>> mChooserTargetScores = new HashMap<>();
private Set<ComponentName> mPendingChooserTargetService = new HashSet<>();
private Set<ComponentName> mShortcutComponents = new HashSet<>();
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
- private final List<TargetInfo> mCallerTargets = new ArrayList<>();
+ private final List<DisplayResolveInfo> mCallerTargets = new ArrayList<>();
private final ChooserActivity.BaseChooserTargetComparator mBaseTargetComparator =
new ChooserActivity.BaseChooserTargetComparator();
@@ -235,8 +238,9 @@
}
@Override
- protected void onBindView(View view, TargetInfo info) {
- super.onBindView(view, info);
+ protected void onBindView(View view, TargetInfo info, int position) {
+ super.onBindView(view, info, position);
+ if (info == null) return;
// If target is loading, show a special placeholder shape in the label, make unclickable
final ViewHolder holder = (ViewHolder) view.getTag();
@@ -253,28 +257,49 @@
holder.text.setBackground(null);
holder.itemView.setBackground(holder.defaultItemViewBackground);
}
+
+ if (info instanceof MultiDisplayResolveInfo) {
+ // If the target is grouped show an indicator
+ Drawable bkg = mContext.getDrawable(R.drawable.chooser_group_background);
+ holder.text.setPaddingRelative(0, 0, bkg.getIntrinsicWidth() /* end */, 0);
+ holder.text.setBackground(bkg);
+ } else if (info.isPinned() && getPositionTargetType(position) == TARGET_STANDARD) {
+ // If the target is pinned and in the suggested row show a pinned indicator
+ Drawable bkg = mContext.getDrawable(R.drawable.chooser_pinned_background);
+ holder.text.setPaddingRelative(bkg.getIntrinsicWidth() /* start */, 0, 0, 0);
+ holder.text.setBackground(bkg);
+ } else {
+ holder.text.setBackground(null);
+ holder.text.setPaddingRelative(0, 0, 0, 0);
+ }
}
void updateAlphabeticalList() {
mSortedList.clear();
+ List<DisplayResolveInfo> tempList = new ArrayList<>();
+ tempList.addAll(mDisplayList);
+ tempList.addAll(mCallerTargets);
if (mEnableStackedApps) {
// Consolidate multiple targets from same app.
Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
- for (DisplayResolveInfo info : mDisplayList) {
+ for (DisplayResolveInfo info : tempList) {
String packageName = info.getResolvedComponentName().getPackageName();
- if (consolidated.get(packageName) != null) {
- // create consolidated target
- MultiDisplayResolveInfo multiDisplayResolveInfo =
- new MultiDisplayResolveInfo(packageName, info);
- multiDisplayResolveInfo.addTarget(consolidated.get(packageName));
- consolidated.put(packageName, multiDisplayResolveInfo);
- } else {
+ DisplayResolveInfo multiDri = consolidated.get(packageName);
+ if (multiDri == null) {
consolidated.put(packageName, info);
+ } else if (multiDri instanceof MultiDisplayResolveInfo) {
+ ((MultiDisplayResolveInfo) multiDri).addTarget(info);
+ } else {
+ // create consolidated target from the single DisplayResolveInfo
+ MultiDisplayResolveInfo multiDisplayResolveInfo =
+ new MultiDisplayResolveInfo(packageName, multiDri);
+ multiDisplayResolveInfo.addTarget(info);
+ consolidated.put(packageName, multiDisplayResolveInfo);
}
}
mSortedList.addAll(consolidated.values());
} else {
- mSortedList.addAll(mDisplayList);
+ mSortedList.addAll(tempList);
}
Collections.sort(mSortedList, new ChooserActivity.AzInfoComparator(mContext));
}
@@ -326,7 +351,10 @@
return standardCount > mChooserListCommunicator.getMaxRankedTargets() ? standardCount : 0;
}
- int getRankedTargetCount() {
+ /**
+ * Fetch ranked app target count
+ */
+ public int getRankedTargetCount() {
int spacesAvailable =
mChooserListCommunicator.getMaxRankedTargets() - getCallerTargetCount();
return Math.min(spacesAvailable, super.getCount());
@@ -411,6 +439,19 @@
return null;
}
+ // Check whether {@code dri} should be added into mDisplayList.
+ @Override
+ protected boolean shouldAddResolveInfo(DisplayResolveInfo dri) {
+ // Checks if this info is already listed in callerTargets.
+ for (TargetInfo existingInfo : mCallerTargets) {
+ if (mResolverListCommunicator
+ .resolveInfoMatch(dri.getResolveInfo(), existingInfo.getResolveInfo())) {
+ return false;
+ }
+ }
+ return super.shouldAddResolveInfo(dri);
+ }
+
/**
* Fetch surfaced direct share target info
*/
@@ -570,7 +611,13 @@
Pair<List<ChooserTargetInfo>, Integer> parkingTargetInfoPair =
mParkingDirectShareTargets.getOrDefault(origComponentName,
new Pair<>(new ArrayList<>(), 0));
- parkingTargetInfoPair.first.addAll(parkingTargetInfos);
+ for (ChooserTargetInfo target : parkingTargetInfos) {
+ if (!checkDuplicateTarget(target, parkingTargetInfoPair.first)
+ && !checkDuplicateTarget(target, mServiceTargets)) {
+ parkingTargetInfoPair.first.add(target);
+ mAvailableServiceTargetsNum++;
+ }
+ }
mParkingDirectShareTargets.put(origComponentName, parkingTargetInfoPair);
rankTargetsWithinComponent(origComponentName);
if (isShortcutResult) {
@@ -615,7 +662,7 @@
List<ChooserTargetInfo> parkingTargets = parkingTargetsItem.first;
int insertedNum = parkingTargetsItem.second;
while (insertedNum < quota && !parkingTargets.isEmpty()) {
- if (!checkDuplicateTarget(parkingTargets.get(0))) {
+ if (!checkDuplicateTarget(parkingTargets.get(0), mServiceTargets)) {
mServiceTargets.add(mValidServiceTargetsNum, parkingTargets.get(0));
mValidServiceTargetsNum++;
insertedNum++;
@@ -630,9 +677,6 @@
+ " totalScore=" + totalScore
+ " quota=" + quota);
}
- if (mShortcutComponents.contains(component)) {
- mNumShortcutResults += insertedNum - parkingTargetsItem.second;
- }
mParkingDirectShareTargets.put(component, new Pair<>(parkingTargets, insertedNum));
}
if (!shouldWaitPendingService) {
@@ -648,19 +692,15 @@
return;
}
Log.i(TAG, " fillAllServiceTargets");
- int maxRankedTargets = mChooserListCommunicator.getMaxRankedTargets();
- List<ComponentName> topComponentNames = getTopComponentNames(maxRankedTargets);
+ List<ComponentName> topComponentNames = getTopComponentNames(MAX_SERVICE_TARGET_APP);
// Append all remaining targets of top recommended components into direct share row.
for (ComponentName component : topComponentNames) {
if (!mParkingDirectShareTargets.containsKey(component)) {
continue;
}
mParkingDirectShareTargets.get(component).first.stream()
- .filter(target -> !checkDuplicateTarget(target))
+ .filter(target -> !checkDuplicateTarget(target, mServiceTargets))
.forEach(target -> {
- if (mShortcutComponents.contains(component)) {
- mNumShortcutResults++;
- }
mServiceTargets.add(mValidServiceTargetsNum, target);
mValidServiceTargetsNum++;
});
@@ -673,28 +713,34 @@
.map(pair -> pair.first)
.forEach(targets -> {
for (ChooserTargetInfo target : targets) {
- if (!checkDuplicateTarget(target)) {
+ if (!checkDuplicateTarget(target, mServiceTargets)) {
mServiceTargets.add(mValidServiceTargetsNum, target);
mValidServiceTargetsNum++;
- mNumShortcutResults++;
}
}
});
mParkingDirectShareTargets.clear();
}
- private boolean checkDuplicateTarget(ChooserTargetInfo chooserTargetInfo) {
+ private boolean checkDuplicateTarget(ChooserTargetInfo target,
+ List<ChooserTargetInfo> destination) {
// Check for duplicates and abort if found
- for (ChooserTargetInfo otherTargetInfo : mServiceTargets) {
- if (chooserTargetInfo.isSimilar(otherTargetInfo)) {
+ for (ChooserTargetInfo otherTargetInfo : destination) {
+ if (target.isSimilar(otherTargetInfo)) {
return true;
}
}
return false;
}
- int getNumShortcutResults() {
- return mNumShortcutResults;
+ /**
+ * The return number have to exceed a minimum limit to make direct share area expandable. When
+ * append direct share targets is enabled, return count of all available targets parking in the
+ * memory; otherwise, it is shortcuts count which will help reduce the amount of visible
+ * shuffling due to older-style direct share targets.
+ */
+ int getNumServiceTargetsForExpand() {
+ return mAppendDirectShareEnabled ? mAvailableServiceTargetsNum : mNumShortcutResults;
}
/**
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 57157f7..774be3c 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -37,15 +37,18 @@
private static final int SINGLE_CELL_SPAN_SIZE = 1;
private final ChooserProfileDescriptor[] mItems;
+ private final boolean mIsSendAction;
ChooserMultiProfilePagerAdapter(Context context,
ChooserActivity.ChooserGridAdapter adapter,
UserHandle personalProfileUserHandle,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ boolean isSendAction) {
super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle);
mItems = new ChooserProfileDescriptor[] {
createProfileDescriptor(adapter)
};
+ mIsSendAction = isSendAction;
}
ChooserMultiProfilePagerAdapter(Context context,
@@ -53,13 +56,15 @@
ChooserActivity.ChooserGridAdapter workAdapter,
@Profile int defaultProfile,
UserHandle personalProfileUserHandle,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ boolean isSendAction) {
super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
workProfileUserHandle);
mItems = new ChooserProfileDescriptor[] {
createProfileDescriptor(personalAdapter),
createProfileDescriptor(workAdapter)
};
+ mIsSendAction = isSendAction;
}
private ChooserProfileDescriptor createProfileDescriptor(
@@ -182,34 +187,62 @@
@Override
protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
- showEmptyState(activeListAdapter,
- R.drawable.ic_sharing_disabled,
- R.string.resolver_cant_share_with_work_apps,
- R.string.resolver_cant_share_with_work_apps_explanation);
+ if (mIsSendAction) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_share_with_work_apps,
+ R.string.resolver_cant_share_with_work_apps_explanation);
+ } else {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_access_work_apps,
+ R.string.resolver_cant_access_work_apps_explanation);
+ }
}
@Override
protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
- showEmptyState(activeListAdapter,
- R.drawable.ic_sharing_disabled,
- R.string.resolver_cant_share_with_personal_apps,
- R.string.resolver_cant_share_with_personal_apps_explanation);
+ if (mIsSendAction) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_share_with_personal_apps,
+ R.string.resolver_cant_share_with_personal_apps_explanation);
+ } else {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_access_personal_apps,
+ R.string.resolver_cant_access_personal_apps_explanation);
+ }
}
@Override
protected void showNoPersonalAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
- showEmptyState(listAdapter,
- R.drawable.ic_no_apps,
- R.string.resolver_no_personal_apps_available_share,
- /* subtitleRes */ 0);
+ if (mIsSendAction) {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_personal_apps_available_share,
+ /* subtitleRes */ 0);
+ } else {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_personal_apps_available_resolve,
+ /* subtitleRes */ 0);
+ }
}
@Override
protected void showNoWorkAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
- showEmptyState(listAdapter,
- R.drawable.ic_no_apps,
- R.string.resolver_no_work_apps_available_share,
- /* subtitleRes */ 0);
+ if (mIsSendAction) {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_work_apps_available_share,
+ /* subtitleRes */ 0);
+ } else {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_work_apps_available_resolve,
+ /* subtitleRes */ 0);
+ }
}
class ChooserProfileDescriptor extends ProfileDescriptor {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 2f62f8e..4b5735c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -182,6 +182,8 @@
private BroadcastReceiver mWorkProfileStateReceiver;
private UserHandle mHeaderCreatorUser;
+ private UserHandle mWorkProfileUserHandle;
+
/**
* Get the string resource to be used as a label for the link to the resolver activity for an
* action.
@@ -322,7 +324,7 @@
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, int defaultTitleRes, Intent[] initialIntents,
List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
- setTheme(R.style.Theme_DeviceDefault_Resolver);
+ setTheme(appliedThemeResId());
super.onCreate(savedInstanceState);
// Determine whether we should show that intent is forwarded
@@ -356,13 +358,15 @@
: isHttpSchemeAndViewAction(getTargetIntent());
mSupportsAlwaysUseOption = supportsAlwaysUseOption;
+ mWorkProfileUserHandle = fetchWorkProfileUserProfile();
// The last argument of createResolverListAdapter is whether to do special handling
// of the last used choice to highlight it in the list. We need to always
// turn this off when running under voice interaction, since it results in
// a more complicated UI that the current voice interaction flow is not able
- // to handle.
- boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
+ // to handle. We also turn it off when the work tab is shown to simplify the UX.
+ boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction()
+ && !shouldShowTabs();
mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
if (configureContentView()) {
return;
@@ -503,6 +507,10 @@
/* shouldShowNoCrossProfileIntentsEmptyState= */ getUser().equals(intentUser));
}
+ protected int appliedThemeResId() {
+ return R.style.Theme_DeviceDefault_Resolver;
+ }
+
/**
* Returns the user id of the user that the starting intent originated from.
* <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()},
@@ -527,13 +535,18 @@
return UserHandle.of(ActivityManager.getCurrentUser());
}
protected @Nullable UserHandle getWorkProfileUserHandle() {
+ return mWorkProfileUserHandle;
+ }
+
+ protected @Nullable UserHandle fetchWorkProfileUserProfile() {
+ mWorkProfileUserHandle = null;
UserManager userManager = getSystemService(UserManager.class);
for (final UserInfo userInfo : userManager.getProfiles(ActivityManager.getCurrentUser())) {
if (userInfo.isManagedProfile()) {
- return userInfo.getUserHandle();
+ mWorkProfileUserHandle = userInfo.getUserHandle();
}
}
- return null;
+ return mWorkProfileUserHandle;
}
private boolean hasWorkProfile() {
@@ -1603,6 +1616,7 @@
}
private void setupProfileTabs() {
+ maybeHideDivider();
TabHost tabHost = findViewById(R.id.profile_tabhost);
tabHost.setup();
ViewPager viewPager = findViewById(R.id.profile_pager);
@@ -1651,6 +1665,17 @@
findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
}
+ private void maybeHideDivider() {
+ if (!isIntentPicker()) {
+ return;
+ }
+ final View divider = findViewById(R.id.divider);
+ if (divider == null) {
+ return;
+ }
+ divider.setVisibility(View.GONE);
+ }
+
/**
* Callback called when user changes the profile tab.
* <p>This method is intended to be overridden by subclasses.
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 2fd938f..d942e85 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -54,6 +54,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.SelectableTargetInfo;
import com.android.internal.app.chooser.TargetInfo;
import java.util.ArrayList;
@@ -84,7 +85,7 @@
private int mLastChosenPosition = -1;
private boolean mFilterLastUsed;
- private final ResolverListCommunicator mResolverListCommunicator;
+ final ResolverListCommunicator mResolverListCommunicator;
private Runnable mPostListReadyRunnable;
private final boolean mIsAudioCaptureDevice;
private boolean mIsTabLoaded;
@@ -442,17 +443,24 @@
// TODO(arangelov): Is that UserHandle.USER_CURRENT check okay?
if (dri != null && dri.getResolveInfo() != null
&& dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) {
- // Checks if this info is already listed in display.
- for (DisplayResolveInfo existingInfo : mDisplayList) {
- if (mResolverListCommunicator
- .resolveInfoMatch(dri.getResolveInfo(), existingInfo.getResolveInfo())) {
- return;
- }
+ if (shouldAddResolveInfo(dri)) {
+ mDisplayList.add(dri);
}
- mDisplayList.add(dri);
}
}
+ // Check whether {@code dri} should be added into mDisplayList.
+ protected boolean shouldAddResolveInfo(DisplayResolveInfo dri) {
+ // Checks if this info is already listed in display.
+ for (DisplayResolveInfo existingInfo : mDisplayList) {
+ if (mResolverListCommunicator
+ .resolveInfoMatch(dri.getResolveInfo(), existingInfo.getResolveInfo())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Nullable
public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
TargetInfo target = targetInfoForPosition(position, filtered);
@@ -516,7 +524,7 @@
if (view == null) {
view = createView(parent);
}
- onBindView(view, getItem(position));
+ onBindView(view, getItem(position), position);
return view;
}
@@ -533,10 +541,10 @@
}
public final void bindView(int position, View view) {
- onBindView(view, getItem(position));
+ onBindView(view, getItem(position), position);
}
- protected void onBindView(View view, TargetInfo info) {
+ protected void onBindView(View view, TargetInfo info, int position) {
final ViewHolder holder = (ViewHolder) view.getTag();
if (info == null) {
holder.icon.setImageDrawable(
@@ -549,6 +557,15 @@
getLoadLabelTask((DisplayResolveInfo) info, holder).execute();
} else {
holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo());
+ if (info instanceof SelectableTargetInfo) {
+ // direct share targets should append the application name for a better readout
+ DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo();
+ CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : "";
+ CharSequence extendedInfo = info.getExtendedInfo();
+ String contentDescription = String.join(" ", info.getDisplayLabel(),
+ extendedInfo != null ? extendedInfo : "", appName);
+ holder.updateContentDescription(contentDescription);
+ }
}
if (info.isSuspended()) {
@@ -697,6 +714,12 @@
text2.setVisibility(View.VISIBLE);
text2.setText(subLabel);
}
+
+ itemView.setContentDescription(null);
+ }
+
+ public void updateContentDescription(String description) {
+ itemView.setContentDescription(description);
}
}
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
index d618cdf..ffe2dbe 100644
--- a/core/java/com/android/internal/app/SimpleIconFactory.java
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -20,6 +20,7 @@
import static android.graphics.Paint.DITHER_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -46,6 +47,7 @@
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Pools.SynchronizedPool;
+import android.util.TypedValue;
import com.android.internal.R;
@@ -92,10 +94,8 @@
final ActivityManager am = (ActivityManager) ctx.getSystemService(ACTIVITY_SERVICE);
final int iconDpi = (am == null) ? 0 : am.getLauncherLargeIconDensity();
- final Resources r = ctx.getResources();
- final int iconSize = r.getDimensionPixelSize(R.dimen.resolver_icon_size);
- final int badgeSize = r.getDimensionPixelSize(R.dimen.resolver_badge_size);
-
+ final int iconSize = getIconSizeFromContext(ctx);
+ final int badgeSize = getBadgeSizeFromContext(ctx);
instance = new SimpleIconFactory(ctx, iconDpi, iconSize, badgeSize);
instance.setWrapperBackgroundColor(Color.WHITE);
}
@@ -103,6 +103,27 @@
return instance;
}
+ private static int getAttrDimFromContext(Context ctx, @AttrRes int attrId, String errorMsg) {
+ final Resources res = ctx.getResources();
+ TypedValue outVal = new TypedValue();
+ if (!ctx.getTheme().resolveAttribute(attrId, outVal, true)) {
+ throw new IllegalStateException(errorMsg);
+ }
+ return res.getDimensionPixelSize(outVal.resourceId);
+ }
+
+ private static int getIconSizeFromContext(Context ctx) {
+ return getAttrDimFromContext(ctx,
+ com.android.internal.R.attr.iconfactoryIconSize,
+ "Expected theme to define iconfactoryIconSize.");
+ }
+
+ private static int getBadgeSizeFromContext(Context ctx) {
+ return getAttrDimFromContext(ctx,
+ com.android.internal.R.attr.iconfactoryBadgeSize,
+ "Expected theme to define iconfactoryBadgeSize.");
+ }
+
/**
* Recycles the SimpleIconFactory so others may use it.
*
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 246a07d..900e18d 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -44,7 +44,6 @@
import com.android.internal.app.SimpleIconFactory;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -136,6 +135,10 @@
return mIsSuspended;
}
+ public DisplayResolveInfo getDisplayResolveInfo() {
+ return mSourceInfo;
+ }
+
private Drawable getChooserTargetIconDrawable(ChooserTarget target,
@Nullable ShortcutInfo shortcutInfo) {
Drawable directShareIcon = null;
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 6f33096..d238d0e 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -61,22 +61,6 @@
public static final String SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS =
"screenshot_notification_smart_actions_timeout_ms";
- // Flags related to controls
-
- /**
- * (boolean) Whether to have split behavior when opening QS
- */
- public static final String QS_SPLIT_ENABLED = "qs_split_enabled";
-
- /**
- * (int) Open settings panels for WiFi and BT tiles
- * 0 - default behavior, link to settings
- * 1 - open panel on long press, click remains the same
- * 2 - open panel on click, long press remains the same
- * 3 - use details on long press
- */
- public static final String QS_USE_SETTINGS_PANELS = "qs_use_settings_panels";
-
// Flags related to Smart Suggestions - these are read in SmartReplyConstants.
/** (boolean) Whether to enable smart suggestions in notifications. */
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 2f048c9..a50a522 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -68,6 +68,7 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Predicate;
import java.util.regex.Pattern;
/**
@@ -381,17 +382,51 @@
return result;
}
+ /**
+ * This method is similar to
+ * {@link DocumentsProvider#queryChildDocuments(String, String[], String)}. This method returns
+ * all children documents including hidden directories/files.
+ *
+ * <p>
+ * In a scoped storage world, access to "Android/data" style directories are hidden for privacy
+ * reasons. This method may show privacy sensitive data, so its usage should only be in
+ * restricted modes.
+ *
+ * @param parentDocumentId the directory to return children for.
+ * @param projection list of {@link Document} columns to put into the
+ * cursor. If {@code null} all supported columns should be
+ * included.
+ * @param sortOrder how to order the rows, formatted as an SQL
+ * {@code ORDER BY} clause (excluding the ORDER BY itself).
+ * Passing {@code null} will use the default sort order, which
+ * may be unordered. This ordering is a hint that can be used to
+ * prioritize how data is fetched from the network, but UI may
+ * always enforce a specific ordering
+ * @throws FileNotFoundException when parent document doesn't exist or query fails
+ */
+ protected Cursor queryChildDocumentsShowAll(
+ String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+ return queryChildDocuments(parentDocumentId, projection, sortOrder, File -> true);
+ }
+
@Override
public Cursor queryChildDocuments(
String parentDocumentId, String[] projection, String sortOrder)
throws FileNotFoundException {
+ // Access to some directories is hidden for privacy reasons.
+ return queryChildDocuments(parentDocumentId, projection, sortOrder, this::shouldShow);
+ }
+ private Cursor queryChildDocuments(
+ String parentDocumentId, String[] projection, String sortOrder,
+ @NonNull Predicate<File> filter) throws FileNotFoundException {
final File parent = getFileForDocId(parentDocumentId);
final MatrixCursor result = new DirectoryCursor(
resolveProjection(projection), parentDocumentId, parent);
if (parent.isDirectory()) {
for (File file : FileUtils.listFilesOrEmpty(parent)) {
- if (!shouldHide(file)) {
+ if (filter.test(file)) {
includeFile(result, null, file);
}
}
@@ -617,6 +652,10 @@
return (PATTERN_HIDDEN_PATH.matcher(file.getAbsolutePath()).matches());
}
+ private boolean shouldShow(@NonNull File file) {
+ return !shouldHide(file);
+ }
+
protected boolean shouldBlockFromTree(@NonNull String docId) {
return false;
}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 3900f16..7195b45a 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -321,6 +321,20 @@
obtainMessage(AbstractRemoteService::handlePendingRequest, this, asyncRequest));
}
+ /**
+ * Executes an async request immediately instead of sending it to Handler queue as what
+ * {@link scheduleAsyncRequest} does.
+ *
+ * <p>This request is not expecting a callback from the service, hence it's represented by
+ * a simple {@link Runnable}.
+ */
+ protected void executeAsyncRequest(@NonNull AsyncRequest<I> request) {
+ // TODO(b/117779333): fix generics below
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request);
+ handlePendingRequest(asyncRequest);
+ }
+
private void cancelScheduledUnbind() {
mHandler.removeMessages(MSG_UNBIND);
}
diff --git a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
index 1fce098..1ec0206 100644
--- a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
+++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
@@ -91,14 +91,14 @@
int width = right - left;
int height = bottom - top;
if ((ctrlType & CTRL_LEFT) != 0) {
- width = Math.max(minVisibleWidth, width - deltaX);
+ width = Math.max(minVisibleWidth, Math.min(width - deltaX, maxVisibleSize.x));
} else if ((ctrlType & CTRL_RIGHT) != 0) {
- width = Math.max(minVisibleWidth, width + deltaX);
+ width = Math.max(minVisibleWidth, Math.min(width + deltaX, maxVisibleSize.x));
}
if ((ctrlType & CTRL_TOP) != 0) {
- height = Math.max(minVisibleHeight, height - deltaY);
+ height = Math.max(minVisibleHeight, Math.min(height - deltaY, maxVisibleSize.y));
} else if ((ctrlType & CTRL_BOTTOM) != 0) {
- height = Math.max(minVisibleHeight, height + deltaY);
+ height = Math.max(minVisibleHeight, Math.min(height + deltaY, maxVisibleSize.y));
}
// If we have to preserve the orientation - check that we are doing so.
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 38f5f32..8c5fdf5 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -137,7 +137,7 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId);
+ long operationId, int sysUiSessionId);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 24fe063..c320824 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -106,7 +106,7 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId);
+ long operationId, int sysUiSessionId);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index 49c9302..ad6c7e8 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -132,6 +132,7 @@
}
};
}
+
private static final String TAG = "ScreenshotHelper";
// Time until we give up on the screenshot & show an error instead.
@@ -146,8 +147,6 @@
mContext = context;
}
-
-
/**
* Request a screenshot be taken.
*
@@ -284,8 +283,8 @@
break;
case SCREENSHOT_MSG_PROCESS_COMPLETE:
synchronized (mScreenshotLock) {
- if (mScreenshotConnection == myConn) {
- mContext.unbindService(mScreenshotConnection);
+ if (myConn != null && mScreenshotConnection == myConn) {
+ mContext.unbindService(myConn);
mScreenshotConnection = null;
mScreenshotService = null;
}
diff --git a/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl b/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl
index 08a349c..78df3eb 100644
--- a/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl
+++ b/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl
@@ -24,4 +24,6 @@
*/
oneway interface IInlineContentProvider {
void provideContent(int width, int height, in IInlineContentCallback callback);
+ void requestSurfacePackage();
+ void onSurfacePackageReleased();
}
diff --git a/core/java/com/android/internal/widget/GridLayoutManager.java b/core/java/com/android/internal/widget/GridLayoutManager.java
index e0502f1..09e6a99 100644
--- a/core/java/com/android/internal/widget/GridLayoutManager.java
+++ b/core/java/com/android/internal/widget/GridLayoutManager.java
@@ -153,13 +153,11 @@
if (mOrientation == HORIZONTAL) {
info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
glp.getSpanIndex(), glp.getSpanSize(),
- spanGroupIndex, 1,
- mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
+ spanGroupIndex, 1, false, false));
} else { // VERTICAL
info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
spanGroupIndex, 1,
- glp.getSpanIndex(), glp.getSpanSize(),
- mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
+ glp.getSpanIndex(), glp.getSpanSize(), false, false));
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d9b2902..03a7b3d 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1369,7 +1369,7 @@
public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
try {
- getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
+ getLockSettings().registerStrongAuthTracker(strongAuthTracker.getStub());
} catch (RemoteException e) {
throw new RuntimeException("Could not register StrongAuthTracker");
}
@@ -1377,7 +1377,7 @@
public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
try {
- getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
+ getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.getStub());
} catch (RemoteException e) {
Log.e(TAG, "Could not unregister StrongAuthTracker", e);
}
@@ -1740,7 +1740,7 @@
}
}
- protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
+ private final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
@Override
public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
int userId) {
@@ -1755,6 +1755,10 @@
}
};
+ public IStrongAuthTracker.Stub getStub() {
+ return mStub;
+ }
+
private class H extends Handler {
static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
static final int MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED = 2;
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
new file mode 100644
index 0000000..cca39ea
--- /dev/null
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -0,0 +1 @@
+per-file PointerLocationView.java = michaelwr@google.com, svv@google.com
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index fb2ecf3..3f708f8 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -825,18 +825,6 @@
return true;
}
break;
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
- case R.id.accessibilityActionScrollUp:
- if (mCollapseOffset < mCollapsibleHeight) {
- smoothScrollTo(mCollapsibleHeight, 0);
- return true;
- } else if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
- && isDismissable()) {
- smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, 0);
- mDismissOnScrollerFinished = true;
- return true;
- }
- break;
case AccessibilityNodeInfo.ACTION_COLLAPSE:
if (mCollapseOffset < mCollapsibleHeight) {
smoothScrollTo(mCollapsibleHeight, 0);
@@ -886,7 +874,6 @@
}
if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
&& ((mCollapseOffset < mCollapsibleHeight) || isDismissable())) {
- info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD);
info.addAction(AccessibilityAction.ACTION_SCROLL_UP);
info.setScrollable(true);
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index bd7bc4c..5a66f43 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -158,6 +158,7 @@
"android_hardware_camera2_legacy_LegacyCameraDevice.cpp",
"android_hardware_camera2_legacy_PerfMeasurement.cpp",
"android_hardware_camera2_DngCreator.cpp",
+ "android_hardware_display_DisplayManagerGlobal.cpp",
"android_hardware_display_DisplayViewport.cpp",
"android_hardware_HardwareBuffer.cpp",
"android_hardware_SensorManager.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6fcaddf..7b708ef 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -18,39 +18,37 @@
#define LOG_TAG "AndroidRuntime"
#define LOG_NDEBUG 1
-#include <android_runtime/AndroidRuntime.h>
-
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android/graphics/jni_runtime.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <assert.h>
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-#include <utils/misc.h>
-#include <utils/Trace.h>
#include <binder/Parcel.h>
-#include <utils/threads.h>
+#include <bionic/malloc.h>
#include <cutils/properties.h>
-#include <server_configurable_flags/get_flags.h>
-
-#include "jni.h"
+#include <dirent.h>
+#include <dlfcn.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JniInvocation.h>
-#include "android_util_Binder.h"
-
-#include <stdio.h>
+#include <server_configurable_flags/get_flags.h>
#include <signal.h>
+#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <signal.h>
-#include <dirent.h>
-#include <assert.h>
-#include <bionic/malloc.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/misc.h>
+#include <utils/threads.h>
#include <string>
#include <vector>
+#include "android_util_Binder.h"
+#include "jni.h"
+
using namespace android;
using android::base::GetProperty;
@@ -78,6 +76,7 @@
extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env);
extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env);
extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
+extern int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env);
extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_SerialPort(JNIEnv *env);
@@ -653,6 +652,7 @@
char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
char voldDecryptBuf[PROPERTY_VALUE_MAX];
+ char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];
enum {
kEMDefault,
kEMIntPortable,
@@ -767,6 +767,16 @@
addOption("-verbose:gc");
//addOption("-verbose:class");
+ // On Android, we always want to allow loading the PerfettoHprof plugin.
+ // Even with this option set, we will still only actually load the plugin
+ // if we are on a userdebug build or the app is debuggable or profileable.
+ // This is enforced in art/runtime/runtime.cc.
+ //
+ // We want to be able to disable this, because this does not work on host,
+ // and we do not want to enable it in tests.
+ parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=",
+ "true");
+
if (primary_zygote) {
addOption("-Xprimaryzygote");
}
@@ -1519,6 +1529,7 @@
REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice),
REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement),
REG_JNI(register_android_hardware_camera2_DngCreator),
+ REG_JNI(register_android_hardware_display_DisplayManagerGlobal),
REG_JNI(register_android_hardware_HardwareBuffer),
REG_JNI(register_android_hardware_SensorManager),
REG_JNI(register_android_hardware_SerialPort),
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 7ff15f2..d7d8621 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -5,5 +5,16 @@
# Connectivity
per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
+# Display
+per-file android_hardware_display_* = michaelwr@google.com, santoscordon@google.com
+
+# Input
+per-file android_hardware_input* = michaelwr@google.com, svv@google.com
+per-file android_view_Input* = michaelwr@google.com, svv@google.com
+per-file android_view_KeyCharacterMap.* = michaelwr@google.com, svv@google.com
+per-file android_view_*KeyEvent.* = michaelwr@google.com, svv@google.com
+per-file android_view_*MotionEvent.* = michaelwr@google.com, svv@google.com
+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
diff --git a/core/jni/android_hardware_display_DisplayManagerGlobal.cpp b/core/jni/android_hardware_display_DisplayManagerGlobal.cpp
new file mode 100644
index 0000000..9f31671
--- /dev/null
+++ b/core/jni/android_hardware_display_DisplayManagerGlobal.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DisplayManagerGlobal-JNI"
+
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <private/android/choreographer.h>
+
+#include <vector>
+
+#include "core_jni_helpers.h"
+
+using namespace android;
+
+namespace android {
+
+// Dispatches the current refresh rate for the default display to all
+// choreographer instances
+void android_hardware_display_DisplayManagerGlobal_signalNativeCallbacks(JNIEnv* env, jobject,
+ jfloat refreshRate) {
+ const constexpr int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+ const nsecs_t vsyncPeriod = kNanosPerSecond / refreshRate;
+
+ AChoreographer_signalRefreshRateCallbacks(vsyncPeriod);
+}
+
+} // namespace android
+
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/hardware/display/DisplayManagerGlobal";
+
+static const JNINativeMethod gMethods[] = {
+ {"nSignalNativeCallbacks", "(F)V",
+ (void*)android_hardware_display_DisplayManagerGlobal_signalNativeCallbacks},
+};
+
+int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env) {
+ AChoreographer_initJVM(env);
+ return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index c5a4588..22bb210 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1149,6 +1149,21 @@
return N;
}
+static jintArray convertEncapsulationInfoFromNative(JNIEnv *env, uint32_t encapsulationInfo) {
+ std::vector<int> encapsulation;
+ // Ignore the first bit, which is ENCAPSULATION_.*_NONE, as an empty array
+ // should be returned if no encapsulation is supported.
+ encapsulationInfo >>= 1;
+ for (int bitPosition = 1; encapsulationInfo; encapsulationInfo >>= 1, bitPosition++) {
+ if (encapsulationInfo & 1) {
+ encapsulation.push_back(bitPosition);
+ }
+ }
+ jintArray result = env->NewIntArray(encapsulation.size());
+ env->SetIntArrayRegion(result, 0, encapsulation.size(), (jint *)encapsulation.data());
+ return result;
+}
+
static jint convertAudioPortFromNative(JNIEnv *env,
jobject *jAudioPort, const struct audio_port *nAudioPort)
{
@@ -1156,6 +1171,8 @@
jintArray jSamplingRates = NULL;
jintArray jChannelMasks = NULL;
jintArray jChannelIndexMasks = NULL;
+ jintArray jEncapsulationModes = NULL;
+ jintArray jEncapsulationMetadataTypes = NULL;
int* cFormats = NULL;
jintArray jFormats = NULL;
jobjectArray jGains = NULL;
@@ -1316,11 +1333,16 @@
if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
- *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
- jHandle, jDeviceName,
- jSamplingRates, jChannelMasks, jChannelIndexMasks,
- jFormats, jGains,
- nAudioPort->ext.device.type, jAddress);
+ jEncapsulationModes =
+ convertEncapsulationInfoFromNative(env, nAudioPort->ext.device.encapsulation_modes);
+ jEncapsulationMetadataTypes =
+ convertEncapsulationInfoFromNative(env,
+ nAudioPort->ext.device
+ .encapsulation_metadata_types);
+ *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle,
+ jDeviceName, jSamplingRates, jChannelMasks, jChannelIndexMasks,
+ jFormats, jGains, nAudioPort->ext.device.type, jAddress,
+ jEncapsulationModes, jEncapsulationMetadataTypes);
env->DeleteLocalRef(jAddress);
} else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
ALOGV("convertAudioPortFromNative is a mix");
@@ -1362,6 +1384,12 @@
if (jChannelIndexMasks != NULL) {
env->DeleteLocalRef(jChannelIndexMasks);
}
+ if (jEncapsulationModes != NULL) {
+ env->DeleteLocalRef(jEncapsulationModes);
+ }
+ if (jEncapsulationMetadataTypes != NULL) {
+ env->DeleteLocalRef(jEncapsulationMetadataTypes);
+ }
if (cFormats != NULL) {
delete[] cFormats;
}
@@ -2615,8 +2643,10 @@
jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
- gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
- "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+ gAudioDevicePortCstor =
+ GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
+ "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I"
+ "[Landroid/media/AudioGain;ILjava/lang/String;[I[I)V");
// When access AudioPort as AudioDevicePort
gAudioPortFields.mType = GetFieldIDOrDie(env, audioDevicePortClass, "mType", "I");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 36b4b6a..e553a78 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -645,6 +645,14 @@
token->decStrong((void*)nativeAcquireFrameRateFlexibilityToken);
}
+static void nativeSetFixedTransformHint(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jint transformHint) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->setFixedTransformHint(ctrl, transformHint);
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -1644,6 +1652,7 @@
(void*)nativeSetGlobalShadowSettings },
{"nativeGetHandle", "(J)J",
(void*)nativeGetHandle },
+ {"nativeSetFixedTransformHint", "(JJI)V", (void*)nativeSetFixedTransformHint},
};
int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3a5720fd..c5bc083 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1552,8 +1552,8 @@
}
}
-static void BindMountStorageToLowerFs(const userid_t user_id, const char* dir_name,
- const char* package, fail_fn_t fail_fn) {
+static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid,
+ const char* dir_name, const char* package, fail_fn_t fail_fn) {
bool hasSdcardFs = IsFilesystemSupported("sdcardfs");
std::string source;
@@ -1565,6 +1565,9 @@
}
std::string target = StringPrintf("/storage/emulated/%d/%s/%s", user_id, dir_name, package);
+ // As the parent is mounted as tmpfs, we need to create the target dir here.
+ PrepareDirIfNotPresent(target, 0700, uid, uid, fail_fn);
+
if (access(source.c_str(), F_OK) != 0) {
fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno)));
}
@@ -1574,9 +1577,8 @@
BindMount(source, target, fail_fn);
}
-// Bind mount all obb & data directories that are visible to this app.
-// If app data isolation is not enabled for this process, bind mount the whole obb
-// and data directory instead.
+// Mount tmpfs on Android/data and Android/obb, then bind mount all app visible package
+// directories in data and obb directories.
static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) {
@@ -1590,12 +1592,18 @@
fail_fn(CREATE_ERROR("Data package list cannot be empty"));
}
+ // Create tmpfs on Android/obb and Android/data so these 2 dirs won't enter fuse anymore.
+ std::string androidObbDir = StringPrintf("/storage/emulated/%d/Android/obb", user_id);
+ MountAppDataTmpFs(androidObbDir, fail_fn);
+ std::string androidDataDir = StringPrintf("/storage/emulated/%d/Android/data", user_id);
+ MountAppDataTmpFs(androidDataDir, fail_fn);
+
// Bind mount each package obb directory
for (int i = 0; i < size; i += 3) {
jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
std::string packageName = extract_fn(package_str).value();
- BindMountStorageToLowerFs(user_id, "Android/obb", packageName.c_str(), fail_fn);
- BindMountStorageToLowerFs(user_id, "Android/data", packageName.c_str(), fail_fn);
+ BindMountStorageToLowerFs(user_id, uid, "Android/obb", packageName.c_str(), fail_fn);
+ BindMountStorageToLowerFs(user_id, uid, "Android/data", packageName.c_str(), fail_fn);
}
}
@@ -1648,9 +1656,10 @@
uid, process_name, managed_nice_name, fail_fn);
isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
- if (mount_external != MOUNT_EXTERNAL_INSTALLER &&
- mount_external != MOUNT_EXTERNAL_PASS_THROUGH &&
- mount_storage_dirs) {
+ // MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps
+ // will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()),
+ // and hence they won't bind mount storage dirs.
+ if (mount_storage_dirs) {
BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
diff --git a/core/jni/include/android_runtime/AndroidRuntime.h b/core/jni/include/android_runtime/AndroidRuntime.h
index 2351272..d86d934 100644
--- a/core/jni/include/android_runtime/AndroidRuntime.h
+++ b/core/jni/include/android_runtime/AndroidRuntime.h
@@ -19,15 +19,14 @@
#ifndef _RUNTIME_ANDROID_RUNTIME_H
#define _RUNTIME_ANDROID_RUNTIME_H
-#include <utils/Errors.h>
#include <binder/IBinder.h>
-#include <utils/String8.h>
+#include <jni.h>
+#include <pthread.h>
+#include <utils/Errors.h>
#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>
-#include <pthread.h>
-#include <jni.h>
-
namespace android {
@@ -154,6 +153,6 @@
static int javaThreadShell(void* args);
};
-}
+} // namespace android
#endif
diff --git a/core/proto/android/app/tvsettings_enums.proto b/core/proto/android/app/tvsettings_enums.proto
index 30d365c..31c5dd6 100644
--- a/core/proto/android/app/tvsettings_enums.proto
+++ b/core/proto/android/app/tvsettings_enums.proto
@@ -44,6 +44,24 @@
/** Denotes that a toggle is clicked by a user. */
TOGGLE_INTERACTED = 3;
+ /**
+ * Denotes that a TvSettings page is being focused in the forward direction
+ * into the settings tree.
+ */
+ PAGE_FOCUSED_FORWARD = 4;
+
+ /**
+ * Denotes that a TvSettings page is being focused in the backward direction
+ * up the settings tree.
+ */
+ PAGE_FOCUSED_BACKWARD = 5;
+
+ /** Denotes that a toggle is turned on by a user. */
+ TOGGLED_ON = 6;
+
+ /** Denotes that a toggle is turned off by a user. */
+ TOGGLED_OFF = 7;
+
}
/**
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d5384a1..762895b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -169,6 +169,7 @@
optional SettingProto boot_count = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto bugreport_in_power_menu = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto cached_apps_freezer_enabled = 152 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto call_auto_retry = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
message CaptivePortal {
@@ -1059,5 +1060,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 152;
+ // Next tag = 153;
}
diff --git a/core/proto/android/server/usagestatsservice.proto b/core/proto/android/server/usagestatsservice.proto
index f26eefa..e32c07f 100644
--- a/core/proto/android/server/usagestatsservice.proto
+++ b/core/proto/android/server/usagestatsservice.proto
@@ -93,6 +93,8 @@
optional int32 task_root_package_index = 15;
// task_root_class_index contains the index + 1 of the task root class name in the string pool
optional int32 task_root_class_index = 16;
+ // locus_id_index contains the index + 1 of the locus id in the string pool
+ optional int32 locus_id_index = 17;
}
// The following fields contain supplemental data used to build IntervalStats, such as a string
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0bf5045..3cd0f03 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5053,7 +5053,7 @@
android:forceQueryable="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
- android:theme="@style/Theme.DeviceDefault.Resolver"
+ android:theme="@style/Theme.DeviceDefault.Chooser"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:documentLaunchMode="never"
diff --git a/core/res/res/anim/dream_activity_close_exit.xml b/core/res/res/anim/dream_activity_close_exit.xml
new file mode 100644
index 0000000..c4599da
--- /dev/null
+++ b/core/res/res/anim/dream_activity_close_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="100" />
+
diff --git a/core/res/res/anim/dream_activity_open_enter.xml b/core/res/res/anim/dream_activity_open_enter.xml
new file mode 100644
index 0000000..9e1c6e2
--- /dev/null
+++ b/core/res/res/anim/dream_activity_open_enter.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- During this animation we keep the previous activity on the screen
+using a noop animation for it (dream_activity_open_exit). The duration of
+those two has to be the same. -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="0.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+
diff --git a/core/res/res/anim/dream_activity_open_exit.xml b/core/res/res/anim/dream_activity_open_exit.xml
new file mode 100644
index 0000000..740f528
--- /dev/null
+++ b/core/res/res/anim/dream_activity_open_exit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- A noop animation to keep the previous activity alive during the dream
+enter animation. The duration should match the duration of the
+dream_activity_open_enter animation. -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
diff --git a/core/res/res/drawable/chooser_group_background.xml b/core/res/res/drawable/chooser_group_background.xml
new file mode 100644
index 0000000..036028d
--- /dev/null
+++ b/core/res/res/drawable/chooser_group_background.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_chooser_group_arrow"
+ android:gravity="end|center_vertical"
+ android:width="12dp"
+ android:height="12dp"
+ android:start="4dp"
+ android:end="0dp" />
+</layer-list>
diff --git a/core/res/res/drawable/chooser_pinned_background.xml b/core/res/res/drawable/chooser_pinned_background.xml
new file mode 100644
index 0000000..fbbe8c1
--- /dev/null
+++ b/core/res/res/drawable/chooser_pinned_background.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_chooser_pin"
+ android:gravity="start|center_vertical"
+ android:width="12dp"
+ android:height="12dp"
+ android:start="0dp"
+ android:end="4dp" />
+</layer-list>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_chooser_group_arrow.xml b/core/res/res/drawable/ic_chooser_group_arrow.xml
new file mode 100644
index 0000000..d42bb97
--- /dev/null
+++ b/core/res/res/drawable/ic_chooser_group_arrow.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="12dp"
+ android:height="12dp"
+ android:viewportWidth="12"
+ android:viewportHeight="12"
+ android:tint="?attr/textColorSecondary">
+ <path
+ android:pathData="M2,4L6,8L10,4L2,4Z"
+ android:fillColor="#FF000000"/>
+</vector>
diff --git a/core/res/res/drawable/ic_chooser_pin.xml b/core/res/res/drawable/ic_chooser_pin.xml
new file mode 100644
index 0000000..47851dcb
--- /dev/null
+++ b/core/res/res/drawable/ic_chooser_pin.xml
@@ -0,0 +1,26 @@
+<?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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="12dp"
+ android:height="12dp"
+ android:viewportWidth="12"
+ android:viewportHeight="12"
+ android:tint="?attr/textColorSecondary">
+ <path
+ android:pathData="M8.5,2C8.5,1.45 8.055,1 7.5,1L4.5,1C3.95,1 3.5,1.45 3.5,2L3.5,5.5L2.5,7L2.5,8L5.5,8L5.5,10.5L6,11L6.5,10.5L6.5,8L9.5,8L9.5,7L8.5,5.5L8.5,2Z"
+ android:fillColor="#FF000000" />
+</vector>
diff --git a/core/res/res/layout/car_user_switching_dialog.xml b/core/res/res/layout/car_user_switching_dialog.xml
deleted file mode 100644
index d727434..0000000
--- a/core/res/res/layout/car_user_switching_dialog.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:fitsSystemWindows="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/user_loading_avatar"
- android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
- android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"
- android:layout_centerHorizontal="true"/>
-
- <TextView android:id="@+id/user_loading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/car_padding_4"
- android:textSize="@dimen/car_body1_size"
- android:textColor="@color/car_body1"
- android:layout_below="@id/user_loading_avatar"
- android:gravity="center"/>
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/chooser_list_per_profile.xml b/core/res/res/layout/chooser_list_per_profile.xml
index 6b1b002..86dc71c 100644
--- a/core/res/res/layout/chooser_list_per_profile.xml
+++ b/core/res/res/layout/chooser_list_per_profile.xml
@@ -20,7 +20,7 @@
<com.android.internal.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layoutManager="com.android.internal.widget.GridLayoutManager"
+ android:layoutManager="com.android.internal.app.ChooserGridLayoutManager"
android:id="@+id/resolver_list"
android:clipToPadding="false"
android:background="?attr/colorBackgroundFloating"
@@ -29,4 +29,4 @@
android:nestedScrollingEnabled="true" />
<include layout="@layout/resolver_empty_states" />
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index fdd965f..50e6f33 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceSmall"
android:textColor="?attr/textColorPrimary"
- android:textSize="14sp"
+ android:textSize="12sp"
android:gravity="top|center_horizontal"
android:lines="1"
android:ellipsize="end" />
diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml
index fe11769..196a0e8 100644
--- a/core/res/res/layout/resolver_empty_states.xml
+++ b/core/res/res/layout/resolver_empty_states.xml
@@ -59,7 +59,7 @@
<Button
android:id="@+id/resolver_empty_state_button"
android:layout_below="@+id/resolver_empty_state_subtitle"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="8dp"
android:text="@string/resolver_switch_on_work"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 4d0837f..446ce3f 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -83,6 +83,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
+ android:accessibilityTraversalAfter="@id/title"
android:background="?attr/colorBackgroundFloating">
<LinearLayout
android:orientation="vertical"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a1a84ae..787f519 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kragdialoog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Toeganklikheidkortpad op skerm"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Toeganklikheidkortpadkieser op skerm"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Toeganklikheidkortpad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID-ontsluiting suksesvol."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI-ontsluiting suksesvol."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Netwerksubstel se diensverskafferontsluiting suksesvol."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a32e691..ae9a4e9 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1406,7 +1406,7 @@
<string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"የሚከተለው ወይም ተጨማሪ መተግበሪያዎች ወደ መለያህ ለመድረስ አሁን እና ወደፊት ፈቃድ ትጠይቃለህ።"</string>
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"ይህን ጥየቃ መፍቀድ ይፈልጋሉ?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"የመድረሻ ጥያቄ"</string>
- <string name="allow" msgid="6195617008611933762">"ይፍቀዱ"</string>
+ <string name="allow" msgid="6195617008611933762">"ፍቀድ"</string>
<string name="deny" msgid="6632259981847676572">"ያስተባብሉ"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"ፈቃድ ተጠይቋል"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">\n" ለ<xliff:g id="ACCOUNT">%s</xliff:g> መለያ ፈቃድ ተጠይቋል"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"የኃይል መገናኛ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"የማያ ገጽ ላይ ተደራሽነት አቋራጭ"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"የማያ ገጽ ላይ ተደራሽነት አቋራጭ መራጭ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"የተደራሽነት አቋራጭ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሑፍ አሞሌ።"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>፦"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"የICCID መክፈቻ ስኬታማ ነበረ።"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"የIMPI መክፈቻ ስኬታማ ነበረ።"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"የአውታረ መረብ ንኡስ ስብስብ አገልግሎት አቅራቢ መክፈቻ ስኬታማ ነበረ።"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4faac2a..f64e0c9 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -239,7 +239,7 @@
<string name="reboot_safemode_title" msgid="5853949122655346734">"إعادة تشغيل في الوضع الآمن"</string>
<string name="reboot_safemode_confirm" msgid="1658357874737219624">"هل تريد إعادة تشغيل الكمبيوتر في الوضع الآمن؟ سيؤدي ذلك إلى إيقاف جميع تطبيقات الجهات الخارجية التي تم تثبيتها. ستتم استعادتها عند إعادة التشغيل مرة أخرى."</string>
<string name="recent_tasks_title" msgid="8183172372995396653">"حديثة"</string>
- <string name="no_recent_tasks" msgid="9063946524312275906">"ليست هناك تطبيقات حديثة."</string>
+ <string name="no_recent_tasks" msgid="9063946524312275906">"لم يتمّ استخدام تطبيقات مؤخرًا."</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"خيارات الجهاز اللوحي"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"خيارات Android TV"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"خيارات الهاتف"</string>
@@ -1222,7 +1222,7 @@
<string name="whichSendToApplication" msgid="77101541959464018">"إرسال باستخدام"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"إرسال باستخدام %1$s"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"إرسال"</string>
- <string name="whichHomeApplication" msgid="8276350727038396616">"تحديد تطبيق شاشة رئيسية"</string>
+ <string name="whichHomeApplication" msgid="8276350727038396616">"اختيار تطبيق شاشة رئيسية"</string>
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"استخدام %1$s كصفحة رئيسية"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"التقاط صورة"</string>
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"التقاط صورة باستخدام"</string>
@@ -1886,8 +1886,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"لإطالة عمر البطارية، تعمل \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو تقييد النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\".\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو تقييد النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو حظر النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\".\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو حظر النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string>
@@ -2016,7 +2016,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"التطبيق <xliff:g id="APP_NAME_0">%1$s</xliff:g> غير متاح الآن، وهو مُدار بواسطة <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"مزيد من المعلومات"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"استئناف تشغيل التطبيق"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"تفعيل الملف الشخصي للعمل؟"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"هل تريد تفعيل الملف الشخصي للعمل؟"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"سيتم تفعيل تطبيقات العمل التي تستخدمها والإشعارات والبيانات وغيرها من ميزات الملف الشخصي للعمل"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"تفعيل"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
@@ -2178,12 +2178,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"مربّع حوار الطاقة"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"اختصار أدوات تمكين الوصول على الشاشة"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"أداة اختيار اختصارات أدوات تمكين الوصول على الشاشة"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"اختصارات أدوات تمكين الوصول"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2317,4 +2314,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"تم إلغاء قفل ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"تم إلغاء قفل IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"تم إلغاء قفل مقدم خدمة المجموعة الفرعية للشبكة."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b564707..a78e08a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাৱাৰ ডায়লগ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"স্ক্ৰীনত সাধ্য সুবিধাৰ শ্বৰ্টকাট"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"স্ক্ৰীনত সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট বাছনি কৰাৰ সুবিধা"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"সাধ্য সুবিধাৰ শ্বৰ্টকাট"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID আনলক কৰাৰ অনুৰোধ সফল হ\'ল।"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI আনলক কৰাটো সফল হ\'ল।"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"নেটৱৰ্ক ছাবছেট সেৱা প্ৰদানকাৰীক আনলক কৰাটো সফল হ\'ল।"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 0f0c717..06b4010 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Yandırıb-söndürmə dialoqu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranda Əlçatımlılıq Qısayolu"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekranda Əlçatımlılıq Qısayolu Seçicisi"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Əlçatımlılıq Qısayolu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID kilidaçması uğurlu oldu."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI kilidaçması uğurlu oldu."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Şəbəkə alt dəstinin xidmət provayderi kilidaçması uğurlu oldu."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 61342ac..9c45ff3 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2076,12 +2076,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijalog napajanja"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključani ekran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Prečica za pristupačnost na ekranu"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Alatka za biranje prečica za pristupačnost na ekranu"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Prečica za pristupačnost"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2090,7 +2087,7 @@
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupna konverzacija"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string>
- <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovno"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Lični prikaz"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Prikaz za posao"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Ne možete da delite ovaj sadržaj pomoću aplikacija za posao"</string>
@@ -2215,4 +2212,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Otključavanje ICCID-a je uspelo."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Otključavanje IMPI-ja je uspelo."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Zahtev za otključavanje dobavljača usluge podskupa mreže je uspeo."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0fc6572..e22fcee 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дыялогавае акно сілкавання"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Хуткі доступ да спецыяльных магчымасцей на экране"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Налада хуткага доступу да спецыяльных магчымасцей на экране"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Хуткі доступ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Разблакіроўка ICCID выканана."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Разблакіроўка IMPI выканана."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Паслугі аператара падмноства сеткі разблакіраваны."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 579c80d..105c3ea 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Диалогов прозорец за захранването"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Пряк път към достъпността на екрана"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Инструмент за избор на пряк път към достъпността на екрана"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Пряк път за достъпност"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Отключването на ICCID бе успешно."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Отключването на IMPI бе успешно."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Отключването на доставчика на услуги за подмножеството от мрежи бе успешно."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 0505a3e..8c7270b 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1888,8 +1888,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> এখন উপলভ্য নয়। এই অ্যাপটিকে <xliff:g id="APP_NAME_1">%2$s</xliff:g> অ্যাপ ম্যানেজ করে।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"আরও জানুন"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"অ্যাপ আবার চালু করুন"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"কাজের প্রোফাইল চালু করবেন?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"আপনার কাজের অ্যাপ, বিজ্ঞপ্তি, ডেটা এবং কাজের প্রোফাইলের অন্যান্য বৈশিষ্ট্য চালু করা হবে"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"অফিস প্রোফাইল চালু করবেন?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"আপনার অফিস অ্যাপ, বিজ্ঞপ্তি, ডেটা এবং অফিস প্রোফাইলের অন্যান্য বৈশিষ্ট্য চালু করা হবে"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাওয়ার ডায়লগ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"অন-স্ক্রিন অ্যাক্সেসিবিলিটি শর্টকাট"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"অন-স্ক্রিন অ্যাক্সেসিবিলিটি শর্টকাট বেছে নেওয়ার বিকল্প"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"অ্যাক্সেসিবিলিটি শর্টকাট"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID আনলক করা হয়েছে।"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI আনলক করা হয়েছে।"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"নেটওয়ার্ক সাবসেট পরিষেবা প্রদানকারী আনলক করা হয়েছে।"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 23b3cc0..04116a9 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2078,12 +2078,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijaloški okvir za napajanje"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključavanje ekrana"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Prečica za pristupačnost na ekranu"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Okvir za odabir prečice za pristupačnost na ekranu"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Prečica za pristupačnost"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2217,4 +2214,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Otključavanje ICCID-a je uspjelo."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Otključavanje IMPI-ja je uspjelo."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Otključavanje mrežne podgrupe pružaoca usluge je uspjelo."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 23863a5..347633f 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Quadre de diàleg d\'engegada"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Drecera d\'accessibilitat en pantalla"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector de dreceres d\'accessibilitat en pantalla"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Drecera d\'accessibilitat"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"L\'ICCID s\'ha desbloquejat correctament."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"L\'IMPI s\'ha desbloquejat correctament."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"El proveïdor de serveis del subconjunt de la xarxa s\'ha desbloquejat correctament."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 03f3691..7e70874 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogové okno k napájení"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Obrazovka uzamčení"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímek obrazovky"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Zkratka přístupnosti na obrazovce"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Výběr zkratky přístupnosti na obrazovce"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Zkratka přístupnosti"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Odemknutí čísla ICCID proběhlo úspěšně."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Odemknutí identity IMPI proběhlo úspěšně."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Odblokování poskytovatelů služeb pro podskupinu sítí proběhlo úspěšně."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 916565f..e140cd4 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks om strøm"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskærm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Genvej til hjælpefunktioner på skærmen"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Valg af genvej til hjælpefunktioner på skærmen"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Genvej til hjælpefunktioner"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID blev låst op."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI blev låst op."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Tjenesteudbyderens netværksdelmængde blev låst op."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index e5c269e..d94ccc04 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kleines Fenster für Akkustand"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sperrbildschirm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Kurzbefehl für Bildschirmbedienungshilfen"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Auswahl für Kurzbefehle für Bildschirmbedienungshilfen"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Kurzbefehl für Bedienungshilfen"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Untertitelleiste von <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID-Entsperrung war erfolgreich."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI-Entsperrung war erfolgreich."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Entsperrung des subnetz- und mobilfunkanbietergebundenen Geräts war erfolgreich."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6a2ceb3..685a0f0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Παράθυρο διαλόγου λειτουργίας συσκευής"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Οθόνη κλειδώματος"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Στιγμιότυπο οθόνης"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Συντόμευση οθόνης για την προσβασιμότητα"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Επιλογέας συντόμευσης οθόνης για την προσβασιμότητα"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Συντόμευση προσβασιμότητας"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Επιτυχία ξεκλειδώματος ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Επιτυχία ξεκλειδώματος IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Επιτυχία ξεκλειδώματος παρόχου υπηρεσιών υποσυνόλου δικτύου."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 9020dae..2c9e0ef 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"On-screen accessibility shortcut"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"On-screen accessibility shortcut chooser"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Accessibility shortcut"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider unlock successful."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 51397c7..5a17123 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"On-screen accessibility shortcut"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"On-screen accessibility shortcut chooser"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Accessibility shortcut"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider unlock successful."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9020dae..2c9e0ef 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"On-screen accessibility shortcut"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"On-screen accessibility shortcut chooser"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Accessibility shortcut"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider unlock successful."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9020dae..2c9e0ef 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"On-screen accessibility shortcut"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"On-screen accessibility shortcut chooser"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Accessibility shortcut"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider unlock successful."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 9787079..dab5009 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2178,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI unlock successful."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider unlock successful."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a7a0534..c9605e0 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -567,10 +567,10 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella digital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"administrar el hardware de Desbloqueo facial"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"administrar el hardware de desbloqueo facial"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que la app emplee métodos para agregar y borrar plantillas de rostros para su uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"usar el hardware de Desbloqueo facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que la app use el hardware de Desbloqueo facial con fines de autenticación"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"usar el hardware de desbloqueo facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que la app use el hardware de desbloqueo facial con fines de autenticación"</string>
<string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueo facial"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Vuelve a registrar tu rostro"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para mejorar el reconocimiento, vuelve a registrar tu rostro"</string>
@@ -586,8 +586,8 @@
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira directamente al dispositivo."</string>
<string name="face_acquired_not_detected" msgid="2945945257956443257">"Ubica el rostro directamente frente al teléfono."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te estás moviendo demasiado. No muevas el teléfono"</string>
- <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu cara."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ya no se reconoce la cara. Vuelve a intentarlo."</string>
+ <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu rostro."</string>
+ <string name="face_acquired_too_different" msgid="4699657338753282542">"Ya no se reconoce el rostro. Vuelve a intentarlo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Es muy similar a la anterior. Haz otra pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
<string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira la cabeza un poco menos."</string>
@@ -597,15 +597,15 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No se verificó el rostro. Hardware no disponible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Vuelve a probar el Desbloqueo facial."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Vuelve a probar el desbloqueo facial."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"No hay espacio para datos faciales nuevos. Borra uno viejo."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Se canceló el reconocimiento facial."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"El usuario canceló el Desbloqueo facial."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"El usuario canceló el desbloqueo facial."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Demasiados intentos. Se inhabilitó el Desbloqueo facial."</string>
- <string name="face_error_unable_to_process" msgid="5723292697366130070">"No se pudo verificar la cara. Vuelve a intentarlo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"No configuraste el Desbloqueo facial."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"No se admite el Desbloqueo facial en este dispositivo."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Demasiados intentos. Se inhabilitó el desbloqueo facial."</string>
+ <string name="face_error_unable_to_process" msgid="5723292697366130070">"No se pudo verificar el rostro. Vuelve a intentarlo."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"No configuraste el desbloqueo facial."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"No se admite el desbloqueo facial en este dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Se inhabilitó temporalmente el sensor."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rostro <xliff:g id="FACEID">%d</xliff:g>"</string>
<string-array name="face_error_vendor">
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reanudar app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Se activaran las apps de trabajo, los datos, las notificaciones y otras funciones del perfil de trabajo"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Se activarán las apps de trabajo, los datos, las notificaciones y otras funciones del perfil de trabajo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Diálogo de encendido"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear pantalla"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Acceso directo de accesibilidad en pantalla"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector del acceso directo de accesibilidad en pantalla"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Acceso directo de accesibilidad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Se desbloqueó correctamente el dispositivo para ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Se desbloqueó correctamente el dispositivo para IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Se desbloqueó correctamente el dispositivo para el proveedor de servicios del subconjunto de redes."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index a3a9f78..04d6ee3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1661,7 +1661,7 @@
<string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Para cambiar de una función a otra, mantén pulsado el botón Accesibilidad."</string>
<string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Para cambiar de una función a otra, desliza hacia arriba con dos dedos y mantén pulsada la pantalla."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Para cambiar de una función a otra, desliza tres dedos hacia arriba y mantén pulsada la pantalla."</string>
- <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliar"</string>
+ <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliación"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Cerrando la sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1794,8 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para que la batería dure más, Ahorro de batería:\n\n• Activa el tema oscuro\n•Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para que la batería dure más, Ahorro de batería:\n\n• Activa el tema oscuro\n•Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para que la batería dure más, el modo Ahorro de batería hace lo siguiente:\n\n• Activa el tema oscuro\n•Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para que la batería dure más, el modo Ahorro de batería hace lo siguiente:\n\n• Activa el tema oscuro\n• Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"El modo Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que puede reducir el uso de datos. Una aplicación activa puede acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -2000,7 +2000,7 @@
<string name="notification_appops_microphone_active" msgid="581333393214739332">"Micrófono"</string>
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"se muestra sobre otras aplicaciones que haya en la pantalla"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación sobre el modo rutina"</string>
- <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Puede que se agote la batería antes de lo habitual"</string>
+ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Quizás se agote la batería antes de lo habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se ha activado el modo Ahorro de batería para aumentar la duración de la batería"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Ahorro de batería"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Ahorro de batería desactivado"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Abrir cuadro de diálogo"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Acceso directo de accesibilidad en pantalla"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Menú de acceso directo de accesibilidad en pantalla"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Acceso directo de accesibilidad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Desbloqueo de ICCID correcto."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Desbloqueo de IMPI correcto."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Desbloqueo del proveedor de servicios de subconjunto de red correcto."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index ddb89af..0d2cdea 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Energiasäästja dialoog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekraanil kuvatav juurdepääsetavuse otsetee"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekraanil kuvatav juurdepääsetavuse otsetee valija"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Juurdepääsetavuse otsetee"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID avamine õnnestus."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI avamine õnnestus."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Võrgu alamhulga teenusepakkuja avamise PIN-kood."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 26bbaa5..0a96862 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Piztu edo itzaltzeko leihoa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantaila blokeatua"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pantaila-argazkia"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Pantailako erabilerraztasun-lasterbidea"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Pantailako erabilerraztasun-lasterbideen hautatzailea"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Erabilerraztasun-lasterbidea"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko azpitituluen barra."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Desblokeatu da ICCIDaren bidez."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Desblokeatu da IMPIaren bidez."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Desblokeatu da sareko azpimultzoaren zerbitzu-hornitzailearen bidez."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f77d015..9fb8eff 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -173,10 +173,10 @@
<string name="contentServiceSync" msgid="2341041749565687871">"همگامسازی"</string>
<string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"همگامسازی نشد"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"تعداد <xliff:g id="CONTENT_TYPE">%s</xliff:g> برای حذف بیش از حد مجاز شد."</string>
- <string name="low_memory" product="tablet" msgid="5557552311566179924">"حافظه رایانهٔ لوحی پر است! برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
+ <string name="low_memory" product="tablet" msgid="5557552311566179924">"فضای ذخیرهسازی رایانهٔ لوحی پر است! برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
<string name="low_memory" product="watch" msgid="3479447988234030194">"حافظه ساعت پر است. برای آزادسازی فضا، چند فایل را حذف کنید."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"فضای ذخیرهسازی دستگاه Android TV پر است. برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
- <string name="low_memory" product="default" msgid="2539532364144025569">"حافظه تلفن پر است. بعضی از فایلها را حذف کنید تا فضا آزاد شود."</string>
+ <string name="low_memory" product="default" msgid="2539532364144025569">"فضای ذخیرهسازی تلفن پر است. بعضی از فایلها را حذف کنید تا فضا آزاد شود."</string>
<plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029">
<item quantity="one">مرجع صدور گواهی نصب شد</item>
<item quantity="other">مراجع صدور گواهی نصب شدند</item>
@@ -383,7 +383,7 @@
<string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"به برنامه امکان میدهد قسمتهایی از خود را در حافظه دائمی کند. این کار حافظه موجود را برای سایر برنامهها محدود کرده و باعث کندی تلفن میشود."</string>
<string name="permlab_foregroundService" msgid="1768855976818467491">"اجرای سرویس پیشزمینه"</string>
<string name="permdesc_foregroundService" msgid="8720071450020922795">"به برنامه اجازه میدهد از سرویسهای پیشزمینه استفاده کند."</string>
- <string name="permlab_getPackageSize" msgid="375391550792886641">"اندازه گیری فضای حافظه برنامه"</string>
+ <string name="permlab_getPackageSize" msgid="375391550792886641">"اندازهگیری اندازه فضای ذخیرهسازی برنامه"</string>
<string name="permdesc_getPackageSize" msgid="742743530909966782">"به برنامه اجازه میدهد تا کدها، دادهها و اندازههای حافظهٔ پنهان خود را بازیابی کند"</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"تغییر تنظیمات سیستم"</string>
<string name="permdesc_writeSettings" msgid="8293047411196067188">"به برنامه اجازه میدهد تا دادههای تنظیم سیستم را تغییر دهد. برنامههای مخرب میتوانند پیکربندی سیستم شما را خراب کنند."</string>
@@ -617,10 +617,10 @@
<string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"به برنامه اجازه میدهد تنظیمات همگامسازی را برای حساب تغییر دهد. بهعنوان مثال، از این ویژگی میتوان برای فعال کردن همگامسازی برنامه «افراد» با یک حساب استفاده کرد."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"خواندن اطلاعات آماری همگامسازی"</string>
<string name="permdesc_readSyncStats" msgid="3867809926567379434">"به یک برنامه اجازه میدهد وضعیت همگامسازی یک حساب را بخواند، از جمله سابقه رویدادهای همگامسازی و میزان دادههای همگامسازی شده."</string>
- <string name="permlab_sdcardRead" msgid="5791467020950064920">"خواندن محتوای فضای ذخیره همرسانیشده"</string>
+ <string name="permlab_sdcardRead" msgid="5791467020950064920">"خواندن محتوای فضای ذخیرهسازی مشترک"</string>
<string name="permdesc_sdcardRead" msgid="6872973242228240382">"به برنامه اجازه میدهد محتوای فضای ذخیره همرسانیشدهتان را بخواند."</string>
- <string name="permlab_sdcardWrite" msgid="4863021819671416668">"تغییر یا حذف محتوای فضای ذخیره همرسانیشده"</string>
- <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"به برنامه اجازه میدهد محتوای فضای ذخیره همرسانیشدهتان را بنویسد."</string>
+ <string name="permlab_sdcardWrite" msgid="4863021819671416668">"تغییر یا حذف محتوای فضای ذخیرهسازی مشترک"</string>
+ <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"به برنامه اجازه میدهد محتوای فضای ذخیرهسازی مشترکتان را بنویسد."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"تماس گرفتن/دریافت تماس از طریق SIP"</string>
<string name="permdesc_use_sip" msgid="3590270893253204451">"به برنامه اجازه میدهد تماسهای SIP بگیرد یا دریافت کند."</string>
<string name="permlab_register_sim_subscription" msgid="1653054249287576161">"ثبت ارتباطات سیم کارت مخابراتی جدید"</string>
@@ -694,7 +694,7 @@
<string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"پروکسی کلی دستگاه را برای استفاده هنگام فعال بودن این خطمشی تنظیم میکند. تنها مالک دستگاه میتواند پروکسی کلی را تنظیم کند."</string>
<string name="policylab_expirePassword" msgid="6015404400532459169">"تنظیم تاریخ انقضای گذرواژه قفل صفحه"</string>
<string name="policydesc_expirePassword" msgid="9136524319325960675">"تغییر تعداد دفعاتی که گذرواژه، پین یا الگوی قفل صفحه باید تغییر کند."</string>
- <string name="policylab_encryptedStorage" msgid="9012936958126670110">"تنظیم رمزگذاری حافظه"</string>
+ <string name="policylab_encryptedStorage" msgid="9012936958126670110">"تنظیم رمزگذاری فضای ذخیرهسازی"</string>
<string name="policydesc_encryptedStorage" msgid="1102516950740375617">"اطلاعات ذخیره شده برنامه باید رمزگذاری شود."</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"غیرفعال کردن دوربینها"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"جلوگیری از استفاده از همه دوربینهای دستگاه."</string>
@@ -703,7 +703,7 @@
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"خانه"</item>
<item msgid="7740243458912727194">"تلفن همراه"</item>
- <item msgid="8526146065496663766">"محل کار"</item>
+ <item msgid="8526146065496663766">"کاری"</item>
<item msgid="8150904584178569699">"نمابر محل کار"</item>
<item msgid="4537253139152229577">"نمابر خانه"</item>
<item msgid="6751245029698664340">"پیجو"</item>
@@ -712,7 +712,7 @@
</string-array>
<string-array name="emailAddressTypes">
<item msgid="7786349763648997741">"خانه"</item>
- <item msgid="435564470865989199">"محل کار"</item>
+ <item msgid="435564470865989199">"کاری"</item>
<item msgid="4199433197875490373">"سایر موارد"</item>
<item msgid="3233938986670468328">"سفارشی"</item>
</string-array>
@@ -724,7 +724,7 @@
</string-array>
<string-array name="imAddressTypes">
<item msgid="588088543406993772">"خانه"</item>
- <item msgid="5503060422020476757">"محل کار"</item>
+ <item msgid="5503060422020476757">"کاری"</item>
<item msgid="2530391194653760297">"سایر موارد"</item>
<item msgid="7640927178025203330">"سفارشی"</item>
</string-array>
@@ -746,7 +746,7 @@
<string name="phoneTypeCustom" msgid="5120365721260686814">"سفارشی"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"خانه"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"تلفن همراه"</string>
- <string name="phoneTypeWork" msgid="6604967163358864607">"محل کار"</string>
+ <string name="phoneTypeWork" msgid="6604967163358864607">"کاری"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"نمابر محل کار"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"نمابر خانه"</string>
<string name="phoneTypePager" msgid="576402072263522767">"پیجو"</string>
@@ -761,7 +761,7 @@
<string name="phoneTypeTelex" msgid="2558783611711876562">"تلکس"</string>
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"تلفن همراه محل کار"</string>
- <string name="phoneTypeWorkPager" msgid="3748332310638505234">"پیجوی محل کار"</string>
+ <string name="phoneTypeWorkPager" msgid="3748332310638505234">"پیجوی کاری"</string>
<string name="phoneTypeAssistant" msgid="757550783842231039">"دستیار"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"فراپیام"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"سفارشی"</string>
@@ -770,7 +770,7 @@
<string name="eventTypeOther" msgid="530671238533887997">"سایر موارد"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"سفارشی"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"خانه"</string>
- <string name="emailTypeWork" msgid="2020095414401882111">"محل کار"</string>
+ <string name="emailTypeWork" msgid="2020095414401882111">"کاری"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"سایر موارد"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"تلفن همراه"</string>
<string name="postalTypeCustom" msgid="5645590470242939129">"سفارشی"</string>
@@ -791,7 +791,7 @@
<string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string>
<string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
- <string name="orgTypeWork" msgid="8684458700669564172">"محل کار"</string>
+ <string name="orgTypeWork" msgid="8684458700669564172">"کاری"</string>
<string name="orgTypeOther" msgid="5450675258408005553">"سایر موارد"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"سفارشی"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"سفارشی"</string>
@@ -1107,7 +1107,7 @@
<string name="deleteText" msgid="4200807474529938112">"حذف"</string>
<string name="inputMethod" msgid="1784759500516314751">"روش ورودی"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"کنشهای متنی"</string>
- <string name="low_internal_storage_view_title" msgid="9024241779284783414">"حافظه درحال پر شدن است"</string>
+ <string name="low_internal_storage_view_title" msgid="9024241779284783414">"فضای ذخیرهسازی درحال پر شدن است"</string>
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"فضای ذخیرهسازی سیستم کافی نیست. اطمینان حاصل کنید که دارای ۲۵۰ مگابایت فضای خالی هستید و سیستم را راهاندازی مجدد کنید."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> در حال اجرا است"</string>
@@ -1148,7 +1148,7 @@
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"تصویربرداری با"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"تصویربرداری با %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"تصویربرداری"</string>
- <string name="alwaysUse" msgid="3153558199076112903">"استفاده به صورت پیشفرض برای این عملکرد."</string>
+ <string name="alwaysUse" msgid="3153558199076112903">"استفاده بهصورت پیشفرض برای این عملکرد."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"استتفاده از یک برنامه دیگر"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"پیشفرض را در تنظیمات سیستم> برنامهها> مورد بارگیری شده پاک کنید."</string>
<string name="chooseActivity" msgid="8563390197659779956">"انتخاب عملکرد"</string>
@@ -1427,7 +1427,7 @@
<string name="vpn_text_long" msgid="278540576806169831">"به <xliff:g id="SESSION">%s</xliff:g> متصل شد. برای مدیریت شبکه ضربه بزنید."</string>
<string name="vpn_lockdown_connecting" msgid="6096725311950342607">"در حال اتصال VPN همیشه فعال…"</string>
<string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN همیشه فعال متصل شد"</string>
- <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"ارتباط VPN همیشه روشن قطع شد"</string>
+ <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"از «VPN همیشه روشن» قطع شد"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"به «VPN همیشه روشن» متصل نشد"</string>
<string name="vpn_lockdown_config" msgid="8331697329868252169">"تغییر شبکه یا تنظیمات VPN"</string>
<string name="upload_file" msgid="8651942222301634271">"انتخاب فایل"</string>
@@ -1504,7 +1504,7 @@
<string name="action_menu_overflow_description" msgid="4579536843510088170">"سایر گزینهها"</string>
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="8490227947584914460">"حافظه داخلی مشترک"</string>
+ <string name="storage_internal" msgid="8490227947584914460">"فضای ذخیرهسازی داخلی مشترک"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"کارت SD"</string>
<string name="storage_sd_card_label" msgid="7526153141147470509">"کارت SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"درایو USB"</string>
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"بیشتر بدانید"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"لغو توقف موقت برنامه"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"نمایه کاری روشن شود؟"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"برنامهها، اعلانها، دادهها و سایر قابلیتهای نمایه کاری شما روشن خواهد شد"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"برنامهها، اعلانها، دادهها، و سایر ویژگیهای نمایه کاری شما روشن خواهد شد"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحالحاضر در دسترس نیست."</string>
@@ -1921,7 +1921,7 @@
<string name="app_category_news" msgid="1172762719574964544">"اخبار و مجله"</string>
<string name="app_category_maps" msgid="6395725487922533156">"نقشه و پیمایش"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"بهرهوری"</string>
- <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"حافظه دستگاه"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"فضای ذخیرهسازی دستگاه"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"اشکالزدایی USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ساعت"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"دقیقه"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"کادر گفتگوی روشن/خاموش"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"نماگرفت"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"میانبر دسترسپذیری روی صفحه"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"انتخابگر میانبر دسترسپذیری روی صفحه"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"میانبر دسترسیپذیری"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"قفل ICCID باز شد."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"قفل IMPI باز شد."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"قفل ارائهدهنده خدمات زیرمجموعه شبکه باز شد."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9f50d77..d23a5bd 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -142,7 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-puhelut"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <string name="wifi_calling_off_summary" msgid="5626710010766902560">"Ei käytössä"</string>
+ <string name="wifi_calling_off_summary" msgid="5626710010766902560">"Ei päällä"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Soita Wi-Fin kautta"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Soita mobiiliverkon kautta"</string>
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Vain Wi-Fi"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Virran valintaikkuna"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukitusnäyttö"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Kuvakaappaus"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Näytöllä näkyvä esteettömyyspainike"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Näytöllä näkyvän esteettömyyspainikkeen valitsin"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Esteettömyyspainike"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID:n lukituksen avaaminen onnistui."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI:n lukituksen avaaminen onnistui."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Verkon alijoukon palveluntarjoajan lukituksen avaaminen onnistui."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2a9de66..f1a9b7a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue sur l\'alimentation"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Raccourci d\'accessibilité à l\'écran"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Sélecteur de raccourci d\'accessibilité à l\'écran"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Raccourci d\'accessibilité"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Déverrouillage ICCID effectué."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Déverrouillage IMPI effectué."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Déverrouillage du sous-ensemble du réseau du fournisseur de services effectué."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 224dcfe..8e3440e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1888,7 +1888,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas disponible pour le moment. Cette suspension est gérée par l\'application <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Débloquer l\'application"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Activer profil professionnel ?"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Activer le profil pro. ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, notifications, données et d\'autres fonctionnalités de votre profil professionnel seront activées"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue Marche/Arrêt"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Raccourci d\'accessibilité à l\'écran"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Outil de sélection des raccourcis d\'accessibilité à l\'écran"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Raccourci d\'accessibilité"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Déblocage ICCID effectué."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Déblocage IMPI effectué."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Déblocage du sous-réseau du fournisseur de services effectué."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index cfd555a..29183d0 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1047,8 +1047,8 @@
<item quantity="one">en <xliff:g id="COUNT_0">%d</xliff:g> a</item>
</plurals>
<plurals name="duration_minutes_relative" formatted="false" msgid="6569851308583028344">
- <item quantity="other">hai <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
- <item quantity="one">hai <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
+ <item quantity="other">Hai <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
+ <item quantity="one">Hai <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
</plurals>
<plurals name="duration_hours_relative" formatted="false" msgid="420434788589102019">
<item quantity="other">hai <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Cadro de diálogo de acendido/apagado"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atallo de accesibilidade en pantalla"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector de atallos de accesibilidade en pantalla"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atallo de accesibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"O desbloqueo do ICCID realizouse correctamente."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"O desbloqueo da IMPI realizouse correctamente."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"O desbloqueo do fornecedor de servizo do subconxunto da rede realizouse correctamente."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index cf7afb5..f8b03b3 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -703,7 +703,7 @@
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"ઘર"</item>
<item msgid="7740243458912727194">"મોબાઇલ"</item>
- <item msgid="8526146065496663766">"કાર્યાલય"</item>
+ <item msgid="8526146065496663766">"ઑફિસ"</item>
<item msgid="8150904584178569699">"કાર્ય ફૅક્સ"</item>
<item msgid="4537253139152229577">"ઘરનો ફૅક્સ"</item>
<item msgid="6751245029698664340">"પેજર"</item>
@@ -712,24 +712,24 @@
</string-array>
<string-array name="emailAddressTypes">
<item msgid="7786349763648997741">"હોમ"</item>
- <item msgid="435564470865989199">"કાર્યાલય"</item>
+ <item msgid="435564470865989199">"ઑફિસ"</item>
<item msgid="4199433197875490373">"અન્ય"</item>
<item msgid="3233938986670468328">"કસ્ટમ"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="3861463339764243038">"ઘર"</item>
- <item msgid="5472578890164979109">"કાર્યાલય"</item>
+ <item msgid="5472578890164979109">"ઑફિસ"</item>
<item msgid="5718921296646594739">"અન્ય"</item>
<item msgid="5523122236731783179">"કસ્ટમ"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="588088543406993772">"હોમ"</item>
- <item msgid="5503060422020476757">"કાર્યાલય"</item>
+ <item msgid="5503060422020476757">"ઑફિસ"</item>
<item msgid="2530391194653760297">"અન્ય"</item>
<item msgid="7640927178025203330">"કસ્ટમ"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="6144047813304847762">"કાર્યાલય"</item>
+ <item msgid="6144047813304847762">"ઑફિસ"</item>
<item msgid="7402720230065674193">"અન્ય"</item>
<item msgid="808230403067569648">"કસ્ટમ"</item>
</string-array>
@@ -746,7 +746,7 @@
<string name="phoneTypeCustom" msgid="5120365721260686814">"કસ્ટમ"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"હોમ"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"મોબાઇલ"</string>
- <string name="phoneTypeWork" msgid="6604967163358864607">"કાર્યાલય"</string>
+ <string name="phoneTypeWork" msgid="6604967163358864607">"ઑફિસ"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"કાર્ય ફૅક્સ"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"ઘરનો ફૅક્સ"</string>
<string name="phoneTypePager" msgid="576402072263522767">"પેજર"</string>
@@ -770,16 +770,16 @@
<string name="eventTypeOther" msgid="530671238533887997">"અન્ય"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"કસ્ટમ"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"ઘર"</string>
- <string name="emailTypeWork" msgid="2020095414401882111">"કાર્યાલય"</string>
+ <string name="emailTypeWork" msgid="2020095414401882111">"ઑફિસ"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"અન્ય"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"મોબાઇલ"</string>
<string name="postalTypeCustom" msgid="5645590470242939129">"કસ્ટમ"</string>
<string name="postalTypeHome" msgid="7562272480949727912">"ઘર"</string>
- <string name="postalTypeWork" msgid="8553425424652012826">"કાર્યાલય"</string>
+ <string name="postalTypeWork" msgid="8553425424652012826">"ઑફિસ"</string>
<string name="postalTypeOther" msgid="7094245413678857420">"અન્ય"</string>
<string name="imTypeCustom" msgid="5653384545085765570">"કસ્ટમ"</string>
<string name="imTypeHome" msgid="6996507981044278216">"હોમ"</string>
- <string name="imTypeWork" msgid="2099668940169903123">"કાર્યાલય"</string>
+ <string name="imTypeWork" msgid="2099668940169903123">"ઑફિસ"</string>
<string name="imTypeOther" msgid="8068447383276219810">"અન્ય"</string>
<string name="imProtocolCustom" msgid="4437878287653764692">"કસ્ટમ"</string>
<string name="imProtocolAim" msgid="4050198236506604378">"AIM"</string>
@@ -791,7 +791,7 @@
<string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string>
<string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
- <string name="orgTypeWork" msgid="8684458700669564172">"કાર્યાલય"</string>
+ <string name="orgTypeWork" msgid="8684458700669564172">"ઑફિસ"</string>
<string name="orgTypeOther" msgid="5450675258408005553">"અન્ય"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"કસ્ટમ"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"કસ્ટમ"</string>
@@ -811,7 +811,7 @@
<string name="relationTypeSpouse" msgid="6916682664436031703">"જીવનસાથી"</string>
<string name="sipAddressTypeCustom" msgid="6283889809842649336">"કસ્ટમ"</string>
<string name="sipAddressTypeHome" msgid="5918441930656878367">"ઘર"</string>
- <string name="sipAddressTypeWork" msgid="7873967986701216770">"કાર્યાલય"</string>
+ <string name="sipAddressTypeWork" msgid="7873967986701216770">"ઑફિસ"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"અન્ય"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"આ સંપર્ક જોવા માટે કોઈ ઍપ્લિકેશન મળી નથી."</string>
<string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"પિન કોડ લખો"</string>
@@ -1650,7 +1650,7 @@
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"થઈ ગયું"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"શૉર્ટકટ બંધ કરો"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"શૉર્ટકટનો ઉપયોગ કરો"</string>
- <string name="color_inversion_feature_name" msgid="326050048927789012">"રંગનો વ્યુત્ક્રમ"</string>
+ <string name="color_inversion_feature_name" msgid="326050048927789012">"વિપરીત રંગમાં બદલવું"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"રંગ સુધારણા"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી."</string>
@@ -1784,7 +1784,7 @@
<string name="select_day" msgid="2060371240117403147">"મહિનો અને દિવસ પસંદ કરો"</string>
<string name="select_year" msgid="1868350712095595393">"વર્ષ પસંદ કરો"</string>
<string name="deleted_key" msgid="9130083334943364001">"<xliff:g id="KEY">%1$s</xliff:g> કાઢી નાખી"</string>
- <string name="managed_profile_label_badge" msgid="6762559569999499495">"કાર્યાલય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge" msgid="6762559569999499495">"ઑફિસ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2જું કાર્ય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3જું કાર્ય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"અનપિન કરતા પહેલાં પિન માટે પૂછો"</string>
@@ -1854,7 +1854,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS વિનંતીને વીડિઓ કૉલમાં બદલવામાં આવી છે"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS વિનંતીને USSD વિનંતીમાં બદલવામાં આવી છે"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"નવી SS વિનંતીમાં બદલવામાં આવી છે"</string>
- <string name="notification_work_profile_content_description" msgid="5296477955677725799">"કાર્યાલયની પ્રોફાઇલ"</string>
+ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ઑફિસની પ્રોફાઇલ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"અલર્ટ કરેલ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"વિસ્તૃત કરો"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"સંકુચિત કરો"</string>
@@ -1888,8 +1888,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> હમણાં ઉપલબ્ધ નથી. આને <xliff:g id="APP_NAME_1">%2$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"વધુ જાણો"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ઍપ ફરી શરૂ કરો"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"ઑફિસ માટેની પ્રોફાઇલ ચાલુ કરીએ?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"તમારી ઑફિસ માટેની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય ઑફિસ માટેની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"ઑફિસની પ્રોફાઇલ ચાલુ કરીએ?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"તમારી ઑફિસ માટેની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય ઑફિસની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"પાવર સંવાદ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"સ્ક્રીન પરના ઍક્સેસિબિલિટી શૉર્ટકટ"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"સ્ક્રીન પરના ઍક્સેસિબિલિટી શૉર્ટકટના પસંદકર્તા"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ઍક્સેસિબિલિટી શૉર્ટકટ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2056,7 +2053,7 @@
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ગ્રૂપ વાતચીત"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string>
- <string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ઑફિસ"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"વ્યક્તિગત વ્યૂ"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"ઑફિસ વ્યૂ"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"આને ઑફિસ માટેની ઍપ સાથે શેર કરી શકતાં નથી"</string>
@@ -2067,7 +2064,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"તમારા IT વ્યવસ્થાપક તમને તમારી વ્યક્તિગત પ્રોફાઇલમાંની ઍપ વડે આ કન્ટેન્ટ શેર કરવાની મંજૂરી આપતા નથી"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"વ્યક્તિગત ઍપ વડે આને ખોલી શકતાં નથી"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"તમારા IT વ્યવસ્થાપક તમને તમારી વ્યક્તિગત પ્રોફાઇલમાંની ઍપ વડે આ કન્ટેન્ટ ખોલવાની મંજૂરી આપતા નથી"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"કાર્યાલયની પ્રોફાઇલ થોભાવી છે"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"ઑફિસની પ્રોફાઇલ થોભાવી છે"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"ચાલુ કરો"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"કોઈ ઑફિસ માટેની ઍપ આ કન્ટેન્ટને સપોર્ટ કરી શકતી નથી"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"કોઈ ઑફિસ માટેની ઍપ આ કન્ટેન્ટ ખોલી શકતી નથી"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCIDને અનલૉક કરવાનું સફળ રહ્યું."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPIને અનલૉક કરવાનું સફળ રહ્યું."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"નેટવર્ક સબસેટ સેવા પ્રદાતાના લૉકને અનલૉક કરવાનું સફળ રહ્યું."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5038d72..a15c679 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1796,7 +1796,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
<string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n•गहरे रंग वाली थीम चालू करता है\n•बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या उन्हें बंद कर देता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
<string name="battery_saver_description" msgid="8587408568232177204">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n•गहरे रंग वाली थीम चालू करता है\n•बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या उन्हें बंद कर देता है"</string>
- <string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा सेवर कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकता है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन पर टैप नहीं करते."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन पर टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पावर डायलॉग खोलें"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"स्क्रीन पर दिखने वाला सुलभता का शॉर्टकट"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"स्क्रीन पर दिखने वाले सुलभता के शॉर्टकट को चुनने का मेन्यू"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"सुलभता का शॉर्टकट"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> का कैप्शन बार."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"आईसीसीआईडी को अनलॉक किया गया."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"आईएमपीआई को अनलॉक किया गया."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"नेटवर्क के सबसेट की सेवा देने वाली कंपनी के लॉक को अनलॉक किया गया."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index a458613..a6db95e 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1920,8 +1920,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutačno nije dostupna. Ovime upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Prekini pauzu aplikacije"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Želite uključiti radni profil?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se vaše radne aplikacije, obavijesti, podaci i druge značajke radnog profila"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Želite li uključiti poslovni profil?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se vaše poslovne aplikacije, obavijesti, podaci i druge značajke poslovnog profila"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
@@ -2076,12 +2076,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijalog napajanja"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključajte zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimka zaslona"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Prečac pristupačnosti na zaslonu"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Alat za odabir prečaca pristupačnosti na zaslonu"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Prečac pristupačnosti"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2215,4 +2212,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID je otključan."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI je otključan."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Davatelj usluge podskupa mreže je otključan."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f2e024d..8eb56b4 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Akkumulátorral kapcsolatos párbeszédpanel"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lezárási képernyő"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Képernyőkép"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Képernyőn megjelenő kisegítő lehetőségekre vonatkozó parancs"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Képernyőn megjelenő kisegítő lehetőségekre vonatkozó parancsválasztó"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Kisegítő lehetőségek gyorsparancsa"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2067,7 +2064,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Rendszergazdája nem engedélyezi, hogy ezt a tartalmat a személyes profiljában lévő alkalmazásokkal ossza meg"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Ez a tartalom nem nyitható meg személyes alkalmazásokkal"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Rendszergazdája nem engedélyezi, hogy ezt a tartalmat a személyes profiljában lévő alkalmazásokkal nyissa meg"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"A munkaprofil szüneteltetve van"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"A munkaprofil használata szünetel"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Bekapcsolás"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"A munkahelyi alkalmazások nem támogatják ezt a tartalmat"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Munkahelyi alkalmazásokkal nem nyitható meg ez a tartalom"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Sikerült az ICCID feloldása."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Sikerült az IMPI feloldása."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Sikerült a szolgáltató hálózati alkészletének feloldása."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index bf7ec38..48b088b 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -301,7 +301,7 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"օգտագործել օրացույցը"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"ուղարկել և դիտել SMS-ները"</string>
- <string name="permgrouplab_storage" msgid="1938416135375282333">"Ֆայլեր և մեդիա"</string>
+ <string name="permgrouplab_storage" msgid="1938416135375282333">"Ֆայլեր և մեդիաֆայլեր"</string>
<string name="permgroupdesc_storage" msgid="6351503740613026600">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"Խոսափող"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"ձայնագրել"</string>
@@ -1794,10 +1794,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «OK Google» հրահանգը։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «OK Google» հրահանգը:"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգը։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգը:"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի խնայումը:"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի տնտեսումը"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Միացնել"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Մանրամասն"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Չեղարկել դադարեցումը"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Միացնե՞լ աշխատանքային պրոֆիլը"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիանան"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիացվեն։"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Միացնել"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Սնուցման պատուհան"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Հատուկ գործառույթների դյուրանցում"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Հատուկ գործառույթների դյուրանցման ընտրիչ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Հատուկ գործառույթների դյուրանցում"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID քարտի ապակողպումը հաջողվեց։"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI քարտի ապակողպումը հաջողվեց։"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider քարտի ապակողպումը հաջողվեց։"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index c4ff2e3..f2c34b4 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Daya"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Layar Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Pintasan Aksesibilitas di layar"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Pemilih Pintasan Aksesibilitas di layar"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pintasan Aksesibilitas"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID berhasil dibuka kuncinya."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI berhasil dibuka kuncinya."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Network subset service provider berhasil dibuka."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 168c630..9fb5b78 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Gluggi til að slökkva/endurræsa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Flýtileið í aðgengiseiginleika á skjánum"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Val um flýtileið í aðgengiseiginleika á skjánum"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Flýtileið aðgengisstillingar"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Opnun ICCID tókst."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Opnun IMPI tókst."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Opnun þjónustuaðila netkerfishlutmengis tókst."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index f4794a2..b6be231 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1794,8 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il Tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il Tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Finestra di dialogo Alimentazione"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Schermata di blocco"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Scorciatoia Accessibilità sullo schermo"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selettore scorciatoia Accessibilità sullo schermo"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Scorciatoia Accessibilità"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Sblocco ICCID riuscito."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Sblocco IMPI riuscito."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Sblocco fornitore di servizi sottoinsieme rete riuscito."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c1580da..403bcaf 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"תיבת דו-שיח לגבי הסוללה"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"קיצור דרך לנגישות במסך"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"בורר קיצורי דרך לנגישות במסך"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"קיצור דרך לנגישות"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ביטול הנעילה של ICCID בוצע בהצלחה."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"ביטול הנעילה של IMPI בוצע בהצלחה."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ביטול הנעילה של ספק שירות של תת-קבוצה ברשת בוצע בהצלחה."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 1ba098f..000d03c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1631,8 +1631,8 @@
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能の <xliff:g id="SERVICE">%1$s</xliff:g> が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\nこのショートカットは [設定] > [ユーザー補助] で別の機能に変更できます。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ON にする"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ON にしない"</string>
- <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"オン"</string>
- <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"オフ"</string>
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ON"</string>
+ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"OFF"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> にデバイスのフル コントロールを許可しますか?"</string>
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"<xliff:g id="SERVICE">%1$s</xliff:g> をオンにすると、デバイスデータの暗号化の強化に画面ロックは使用されなくなります。"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"フル コントロールは、ユーザー補助機能を必要とするユーザーをサポートするアプリには適していますが、ほとんどのアプリには適していません。"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"電源ダイアログ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"画面上のユーザー補助のショートカット"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"画面上のユーザー補助のショートカットの選択メニュー"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ユーザー補助のショートカット"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID をロック解除しました。"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI をロック解除しました。"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ネットワーク サブセットのサービス プロバイダをロック解除しました。"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index f216680..3a2d22c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ელკვების დიალოგი"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"მისაწვდომობის ეკრანული მალსახმობი"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"მისაწვდომობის ეკრანული მალსახმობის ამომრჩევი"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"მისაწვდომობის მალსახმობი"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID- წარმატებით შესრულდა."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI-ის განბლოკვა წარმატებით შესრულდა."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ქსელის ყვედანაყოფის სერვისის მომწოდებლის განბლოკვა წარმატებით შესრულდა."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d905d46..1853aba 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Қуат диалогтік терезесі"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Экрандағы арнайы мүмкіндіктерді жылдам қосу"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Экрандағы арнайы мүмкіндіктерді жылдам қосу әрекетін таңдау"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Арнайы мүмкіндіктерді жылдам қосу"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID құлпы ашылды."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI құлпы ашылды."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Қызмет көрсетуші желісінің ішкі жиынтығы құлпы ашылды."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4ec4c14..e544a84 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2044,12 +2044,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ប្រអប់ថាមពល"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ផ្លូវកាត់ភាពងាយស្រួលនៅលើអេក្រង់"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ម៉ឺនុយជ្រើសរើសផ្លូវកាត់ភាពងាយស្រួលនៅលើអេក្រង់"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ផ្លូវកាត់ភាពងាយស្រួល"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string>
@@ -2183,4 +2180,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ការដោះសោ ICCID ទទួលបានជោគជ័យហើយ។"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"ការដោះសោ IMPI ទទួលបានជោគជ័យហើយ។"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ការដោះសោក្រុមហ៊ុនផ្ដល់សេវាសំណុំរងនៃបណ្ដាញទទួលបានជោគជ័យហើយ។"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 5c80684..cc2760f 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ಪವರ್ ಡೈಲಾಗ್"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ಸ್ಕ್ರೀನ್ನಲ್ಲಿನ ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ಸ್ಕ್ರೀನ್ನಲ್ಲಿನ ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಆಯ್ಕೆ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ನ ಶೀರ್ಷಿಕೆಯ ಪಟ್ಟಿ."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID ಅನ್ಲಾಕ್ ಮಾಡುವಿಕೆ ಯಶಸ್ವಿಯಾಗಿದೆ."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI ಅನ್ಲಾಕ್ ಮಾಡುವಿಕೆ ಯಶಸ್ವಿಯಾಗಿದೆ."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ನೆಟ್ವರ್ಕ್ ಸಬ್ಸೆಟ್ ಸೇವಾ ಒದಗಿಸುವವರ ಅನ್ಲಾಕ್ ಮಾಡುವಿಕೆ ಯಶಸ್ವಿಯಾಗಿದೆ."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 79cd4fe..d9f9ee2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"자세히 알아보기"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"앱 일시중지 해제"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"직장 프로필을 사용 설정하시겠어요?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"업무용 앱, 알림, 데이터 및 기타 직장 프로필 기능이 사용 설정됩니다."</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"직장 앱, 알림, 데이터 및 기타 직장 프로필 기능이 사용 설정됩니다."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"사용 설정"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"전원 대화상자"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"화면상의 접근성 바로가기"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"화면상의 접근성 바로가기 선택 도구"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"접근성 단축키"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID 잠금 해제가 완료되었습니다."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI 잠금 해제가 완료되었습니다."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"네트워크 하위 집합 서비스 제공업체 잠금 해제가 완료되었습니다."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 9dc6e46..7cc2958 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -253,8 +253,8 @@
<item quantity="other">Мүчүлүштүк тууралуу кабарлоо үчүн <xliff:g id="NUMBER_1">%d</xliff:g> секундда скриншот алынат.</item>
<item quantity="one">Мүчүлүштүк тууралуу кабарлоо үчүн <xliff:g id="NUMBER_0">%d</xliff:g> секундда скриншот алынат.</item>
</plurals>
- <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Мүчүлүштүк тууралуу кабар берүү үчүн скриншот тартылды"</string>
- <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Мүчүлүштүк тууралуу кабар берүү үчүн скриншот тартылган жок"</string>
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Мүчүлүштүк тууралуу кабарлоо үчүн скриншот тартылды"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Мүчүлүштүк тууралуу кабарлоо үчүн скриншот тартылган жок"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Үнсүз режим"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Добушу ӨЧҮК"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Добушу КҮЙҮК"</string>
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Кеңири маалымат"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Колдонмону иштетүү"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Жумуш профили күйгүзүлсүнбү?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Жумуш колдонмолоруңуз, эскертмелериңиз, дайын-даректериңиз жана жумуш профилинин башка функциялары күйгүзүлөт."</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Жумуш колдонмолоруңуз, билдирмелериңиз, дайын-даректериңиз жана жумуш профилинин башка функциялары күйгүзүлөт."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Күйгүзүү"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
@@ -1922,7 +1922,7 @@
<string name="app_category_maps" msgid="6395725487922533156">"Карталар жана чабыттоо"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Өндүрүш категориясы"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Түзмөктүн сактагычы"</string>
- <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB аркылуу мүчүлүштүктөрдү оңдоо"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB аркылуу мүчүлүштүктөрдү аныктоо"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"саат"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"мүнөт"</string>
<string name="time_picker_header_text" msgid="9073802285051516688">"Убакытты коюу"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Кубат диалогу"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ыкчам иштетүү"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ыкчам иштетүү менюсу"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Ыкчам иштетүү"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID кулпусу ийгиликтүү ачылды."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI кулпусу ийгиликтүү ачылды."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Кичи тармак операторунун кулпусу ийгиликтүү ачылды."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index cd59760..6259e4f 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1230,7 +1230,7 @@
<string name="volume_icon_description_media" msgid="4997633254078171233">"ລະດັບສຽງຂອງສື່"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"ລະດັບສຽງການແຈ້ງເຕືອນ"</string>
<string name="ringtone_default" msgid="9118299121288174597">"ຣິງໂທນເລີ່ມຕົ້ນ"</string>
- <string name="ringtone_default_with_actual" msgid="2709686194556159773">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default_with_actual" msgid="2709686194556159773">"ຄ່າເລີ່ມຕົ້ນ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="397111123930141876">"ບໍ່ມີ"</string>
<string name="ringtone_picker_title" msgid="667342618626068253">"ຣິງໂທນ"</string>
<string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Alarm sounds"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ກ່ອງໂຕ້ຕອບການເປີດປິດ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ທາງລັດການຊ່ວຍເຂົ້າເຖິງຢູ່ໜ້າຈໍ"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ຕົວເລືອກທາງລັດການຊ່ວຍເຂົ້າເຖິງຢູ່ໜ້າຈໍ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ທາງລັດການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ປົດລັອກ ICCID ສຳເລັດແລ້ວ."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"ປົດລັອກ IMPI ສຳເລັດແລ້ວ."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ປົດລັອກຜູ້ໃຫ້ບໍລິການຊຸດຍ່ອຍເຄືອຂ່າຍສຳເລັດແລ້ວ."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e0132e4..636ba18 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Maitinimo dialogo langas"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Užrakinimo ekranas"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrano kopija"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekrano pritaikomumo šaukinys"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekrano pritaikomumo šaukinių parinkiklis"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pritaikomumo šaukinys"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID operatoriaus pasirinkimo ribojimas sėkmingai panaikintas."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI operatoriaus pasirinkimo ribojimas sėkmingai panaikintas."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Tinklo poaibio paslaugos teikėjo operatoriaus pasirinkimo ribojimas sėkmingai panaikintas."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index eeaf12f..fa0bb8b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1231,8 +1231,8 @@
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"<xliff:g id="PROC">%1$s</xliff:g> kaudzes izraksts ir gatavs"</string>
<string name="dump_heap_notification_detail" msgid="8431586843001054050">"Apkopots kaudzes izraksts. Pieskarieties, lai kopīgotu."</string>
<string name="dump_heap_title" msgid="4367128917229233901">"Vai kopīgot kaudzes izrakstu?"</string>
- <string name="dump_heap_text" msgid="1692649033835719336">"Process <xliff:g id="PROC">%1$s</xliff:g> pārsniedza atmiņas ierobežojumu (<xliff:g id="SIZE">%2$s</xliff:g>). Tika apkopots kaudzes izraksts, ko varat kopīgot ar procesa izstrādātāju. Ņemiet vērā: kaudzes izrakstā var būt ietverta jūsu personas informācija, kurai var piekļūt lietojumprogramma."</string>
- <string name="dump_heap_system_text" msgid="6805155514925350849">"Process <xliff:g id="PROC">%1$s</xliff:g> pārsniedza atmiņas ierobežojumu (<xliff:g id="SIZE">%2$s</xliff:g>). Tika apkopots kaudzes izraksts, ko varat kopīgot. Ievērojiet piesardzību, jo kaudzes izrakstā var būt ietverta visa sensitīvā personas informācija, kurai var piekļūt process, tostarp jūsu rakstīts teksts."</string>
+ <string name="dump_heap_text" msgid="1692649033835719336">"Process <xliff:g id="PROC">%1$s</xliff:g> pārsniedza atmiņas ierobežojumu (<xliff:g id="SIZE">%2$s</xliff:g>). Tika vākts kaudzes izraksts, ko varat kopīgot ar procesa izstrādātāju. Ņemiet vērā: kaudzes izrakstā var būt ietverta jūsu personas informācija, kurai var piekļūt lietojumprogramma."</string>
+ <string name="dump_heap_system_text" msgid="6805155514925350849">"Process <xliff:g id="PROC">%1$s</xliff:g> pārsniedza atmiņas ierobežojumu (<xliff:g id="SIZE">%2$s</xliff:g>). Tika vākts kaudzes izraksts, ko varat kopīgot. Ievērojiet piesardzību, jo kaudzes izrakstā var būt ietverta visa sensitīvā personas informācija, kurai var piekļūt process, tostarp jūsu rakstīts teksts."</string>
<string name="dump_heap_ready_text" msgid="5849618132123045516">"Ir pieejams procesa <xliff:g id="PROC">%1$s</xliff:g> kaudzes izraksts, ko varat kopīgot. Ievērojiet piesardzību, jo kaudzes izrakstā var būt ietverta visa sensitīvā personas informācija, kurai var piekļūt process, tostarp jūsu rakstīts teksts."</string>
<string name="sendText" msgid="493003724401350724">"Izvēlieties darbību tekstam"</string>
<string name="volume_ringtone" msgid="134784084629229029">"Zvanītāja skaļums"</string>
@@ -2076,12 +2076,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Barošanas dialoglodziņš"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekrāna pieejamības saīsne"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekrāna pieejamības saīsnes atlasītājs"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pieejamības saīsne"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2215,4 +2212,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID atbloķēšana bija veiksmīga."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI atbloķēšana bija veiksmīga."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Tīkla apakškopas pakalpojuma sniedzēja atbloķēšana bija veiksmīga."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-mcc334-mnc020/config.xml b/core/res/res/values-mcc334-mnc020/config.xml
index 0970517..82b3ee6 100644
--- a/core/res/res/values-mcc334-mnc020/config.xml
+++ b/core/res/res/values-mcc334-mnc020/config.xml
@@ -18,4 +18,7 @@
-->
<resources>
<bool name="config_use_sim_language_file">false</bool>
-</resources>
\ No newline at end of file
+
+ <bool name="config_pdp_reject_enable_retry">true</bool>
+ <integer name="config_pdp_reject_retry_delay_ms">45000</integer>
+</resources>
diff --git a/core/res/res/values-mcc334-mnc020/strings.xml b/core/res/res/values-mcc334-mnc020/strings.xml
new file mode 100644
index 0000000..a8a78d5
--- /dev/null
+++ b/core/res/res/values-mcc334-mnc020/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_pdp_reject_dialog_title"></string>
+ <string name="config_pdp_reject_user_authentication_failed">AUTHENTICATION FAILURE -29-</string>
+ <string name="config_pdp_reject_service_not_subscribed">NOT SUBSCRIBED TO SERVICE -33-</string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed">Multiple PDN connections for a given APN not allowed -55-</string>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 7c0cff1..ab4c1a5 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2044,12 +2044,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дијалог за напојување"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заклучен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Слика од екранот"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Кратенка за пристапност на екранот"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Избирач на кратенка за пристапност на екранот"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Кратенка за пристапност"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2183,4 +2180,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Отклучувањето на ICCID е успешно."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Отклучувањето на IMPI е успешно."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Отклучувањето на операторот на подмножеството на мрежата е успешно."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index bd1193e..9e90637 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"പവർ ഡയലോഗ്"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്ക്രീൻ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"സ്ക്രീനിലെ ഉപയോഗസഹായി കുറുക്കുവഴി"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"സ്ക്രീനിലെ ഉപയോഗസഹായി കുറുക്കുവഴി ചൂസർ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ഉപയോഗസഹായി കുറുക്കുവഴി"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന്റെ അടിക്കുറിപ്പ് ബാർ."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID അൺലോക്ക് ചെയ്തു."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI അൺലോക്ക് ചെയ്തു."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"നെറ്റ്വർക്ക് സബ്സെറ്റ് സേവനദാതാവിനെ അൺലോക്ക് ചെയ്തു."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 51138a7..238a4e6 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -268,7 +268,7 @@
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Шинэ мэдэгдэл"</string>
<string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуал гар"</string>
- <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Бодит гар"</string>
+ <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Биет гар"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Аюулгүй байдал"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Машины горим"</string>
<string name="notification_channel_account" msgid="6436294521740148173">"Бүртгэлийн төлөв"</string>
@@ -1327,7 +1327,7 @@
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"ХУВААЛЦАХ"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ТАТГАЛЗАХ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Оруулах аргыг сонгоно уу"</string>
- <string name="show_ime" msgid="6406112007347443383">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
+ <string name="show_ime" msgid="6406112007347443383">"Биет гар идэвхтэй үед үүнийг дэлгэцэд харуулна уу"</string>
<string name="hardware" msgid="1800597768237606953">"Хийсвэр гарыг харуулах"</string>
<string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"Биет гарыг хэлбэрт оруулах"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Тэжээлийн харилцах цонх"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Дэлгэц дээрх хандалтын товчлол"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Дэлгэц дээрх хандалтын товчлол сонгогч"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Хандалтын товчлол"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID-н түгжээг амжилттай тайллаа."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI-н түгжээг амжилттай тайллаа."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Сүлжээний дэд олонлогийн үйлчилгээ үзүүлэгчийн түгжээг амжилттай тайллаа."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 7943bd4..1840479 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -108,7 +108,7 @@
<string name="serviceClassDataSync" msgid="7895071363569133704">"सिंक करा"</string>
<string name="serviceClassPacket" msgid="1430642951399303804">"पॅकेट"</string>
<string name="serviceClassPAD" msgid="6850244583416306321">"PAD"</string>
- <string name="roamingText0" msgid="7793257871609854208">"रोमिंग दर्शक चालू"</string>
+ <string name="roamingText0" msgid="7793257871609854208">"रोमिंग दर्शक सुरू"</string>
<string name="roamingText1" msgid="5073028598334616445">"रोमिंग दर्शक बंद"</string>
<string name="roamingText2" msgid="2834048284153110598">"रोमिंग दर्शक फ्लॅशिंग"</string>
<string name="roamingText3" msgid="831690234035748988">"अतिपरिचित क्षेत्राबाहेर"</string>
@@ -119,12 +119,12 @@
<string name="roamingText8" msgid="7774800704373721973">"रोमिंग - प्रीमियम भागीदार"</string>
<string name="roamingText9" msgid="1933460020190244004">"रोमिंग - पूर्ण सेवा कार्यक्षमता"</string>
<string name="roamingText10" msgid="7434767033595769499">"रोमिंग - आंशिक सेवा कार्यक्षमता"</string>
- <string name="roamingText11" msgid="5245687407203281407">"रोमिंग बॅनर चालू"</string>
+ <string name="roamingText11" msgid="5245687407203281407">"रोमिंग बॅनर सुरू"</string>
<string name="roamingText12" msgid="673537506362152640">"रोमिंग बॅनर बंद"</string>
<string name="roamingTextSearching" msgid="5323235489657753486">"सेवा शोधत आहे"</string>
<string name="wfcRegErrorTitle" msgid="3193072971584858020">"वाय-फाय कॉलिंग सेट करता आले नाही"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="468830943567116703">"वाय-फायवरून कॉल करण्यासाठी आणि मेसेज पाठवण्यासाठी आधी तुमच्या कॅरियरला ही सेवा सेट अप करण्यास सांगा. नंतर सेटिंग्जमधून वाय-फाय वापरून कॉल करणे पुन्हा चालू करा. (एरर कोड <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="468830943567116703">"वाय-फायवरून कॉल करण्यासाठी आणि मेसेज पाठवण्यासाठी आधी तुमच्या कॅरियरला ही सेवा सेट अप करण्यास सांगा. नंतर सेटिंग्जमधून वाय-फाय वापरून कॉल करणे पुन्हा सुरू करा. (एरर कोड <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="4795145070505729156">"तुमच्या या वाहकासह वाय-फाय कॉलिंग नोंदणी करताना समस्या आली आहे:<xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -209,13 +209,13 @@
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV पर्याय"</string>
<string name="power_dialog" product="default" msgid="1107775420270203046">"फोन पर्याय"</string>
<string name="silent_mode" msgid="8796112363642579333">"मूक मोड"</string>
- <string name="turn_on_radio" msgid="2961717788170634233">"वायरलेस चालू करा"</string>
+ <string name="turn_on_radio" msgid="2961717788170634233">"वायरलेस सुरू करा"</string>
<string name="turn_off_radio" msgid="7222573978109933360">"वायरलेस बंद करा"</string>
<string name="screen_lock" msgid="2072642720826409809">"स्क्रीन लॉक"</string>
<string name="power_off" msgid="4111692782492232778">"बंद करा"</string>
<string name="silent_mode_silent" msgid="5079789070221150912">"रिंगर बंद"</string>
<string name="silent_mode_vibrate" msgid="8821830448369552678">"रिंगर व्हायब्रेट"</string>
- <string name="silent_mode_ring" msgid="6039011004781526678">"रिंगर चालू"</string>
+ <string name="silent_mode_ring" msgid="6039011004781526678">"रिंगर सुरू"</string>
<string name="reboot_to_update_title" msgid="2125818841916373708">"Android सिस्टम अपडेट"</string>
<string name="reboot_to_update_prepare" msgid="6978842143587422365">"अपडेट करण्याची तयारी करत आहे…"</string>
<string name="reboot_to_update_package" msgid="4644104795527534811">"अपडेट पॅकेज प्रक्रिया करत आहे…"</string>
@@ -317,7 +317,7 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"आपल्या महत्त्वाच्या मापनांविषयी सेंसर डेटा अॅक्सेस करा"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विंडोमधील आशय पुन्हा मिळवा"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"तुम्ही वापरत असलेल्या विंडोमधील आशय तपासा."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"स्पर्श करून अन्वेषण चालू करा"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"स्पर्श करून अन्वेषण सुरू करा"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"टॅप केलेले आयटम मोठ्याने बोलले जातील आणि जेश्चरचा वापर करून स्क्रीन एक्सप्लोर केली जाऊ शकते."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"तुम्ही टाइप करता त्या मजकुराचे निरीक्षण करा"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"यामध्ये क्रेडिट कार्ड नंबर आणि पासवर्ड यासारखा वैयक्तिक डेटा समाविष्ट आहे."</string>
@@ -374,7 +374,7 @@
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"हा अॅप इतर अॅप्सच्या शीर्षस्थानी दिसू शकतो."</string>
<string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"हे अॅप इतर अॅप्सच्या शीर्षस्थानी किंवा स्क्रीनच्या इतर भागांवर दिसू शकतो. हे सामान्य अॅप वापरात व्यत्यय आणू शकते किंवा इतर अॅप्सची डिस्प्ले पद्धत बदलू शकते."</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"पार्श्वभूमीत चालवा"</string>
- <string name="permdesc_runInBackground" msgid="4344539472115495141">"हे अॅप पार्श्वभूमीत चालू शकते. हे बॅटरी अधिक जलद संपवू शकते."</string>
+ <string name="permdesc_runInBackground" msgid="4344539472115495141">"हे अॅप पार्श्वभूमीत सुरू शकते. हे बॅटरी अधिक जलद संपवू शकते."</string>
<string name="permlab_useDataInBackground" msgid="783415807623038947">"पार्श्वभूमीत डेटा वापरा"</string>
<string name="permdesc_useDataInBackground" msgid="1230753883865891987">"हे अॅप पार्श्वभूमीत डेटा वापरू शकते. हे डेटाचा वापर वाढवू शकते."</string>
<string name="permlab_persistentActivity" msgid="464970041740567970">"अॅप नेहमी चालवा"</string>
@@ -388,9 +388,9 @@
<string name="permlab_writeSettings" msgid="8057285063719277394">"सिस्टम सेटिंग्ज सुधारित करा"</string>
<string name="permdesc_writeSettings" msgid="8293047411196067188">"सिस्टीमचा सेटिंग्ज डेटा सुधारित करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स आपल्या सिस्टीमचे कॉन्फिगरेशन दूषित करू शकतात."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"सुरूवातीस चालवा"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"जसे सिस्टम बूट करणे समाप्त करते तसे अॅप ला स्वतः प्रारंभ करण्यास अनुमती देते. यामुळे टॅबलेट प्रारंभ करण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर टॅबलेटला धीमे करण्यास अॅप ला अनुमती देते."</string>
- <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"सिस्टम बूट होणे संपल्यावर ॲपला स्वतः सुरू होण्याची अनुमती देते. यामुळे तुमच्या Android TV डिव्हाइसला सुरू होण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर डिव्हाइसलाच धीमे करण्याची अनुमती ॲपला देते."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"जसे सिस्टम बूट करणे समाप्त करते तसे अॅप ला स्वतः प्रारंभ करण्यास अनुमती देते. यामुळे फोन प्रारंभ करण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर फोनला धीमे करण्यास अॅप ला अनुमती देते."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"जसे सिस्टम बूट करणे समाप्त करते तसे अॅप ला स्वतः प्रारंभ करण्यास अनुमती देते. यामुळे टॅबलेट प्रारंभ करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर टॅबलेटला धीमे करण्यास अॅप ला अनुमती देते."</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"सिस्टम बूट होणे संपल्यावर ॲपला स्वतः सुरू होण्याची अनुमती देते. यामुळे तुमच्या Android TV डिव्हाइसला सुरू होण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर डिव्हाइसलाच धीमे करण्याची अनुमती ॲपला देते."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"जसे सिस्टम बूट करणे समाप्त करते तसे अॅप ला स्वतः प्रारंभ करण्यास अनुमती देते. यामुळे फोन प्रारंभ करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर फोनला धीमे करण्यास अॅप ला अनुमती देते."</string>
<string name="permlab_broadcastSticky" msgid="4552241916400572230">"रोचक प्रसारण पाठवा"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"रोचक प्रसारणे पाठविण्यासाठी अॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो टॅब्लेटला धीमा किंवा अस्थिर करू शकतो."</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"चिकट प्रसारणे पाठविण्यासाठी ॲपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो तुमच्या Android TV डिव्हाइसला धीमा किंवा अस्थिर करू शकतो."</string>
@@ -613,7 +613,7 @@
<string name="face_icon_content_description" msgid="465030547475916280">"चेहरा आयकन"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"सिंक सेटिंग्ज वाचा"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"खात्याच्या सिंक सेटिंग्ज वाचण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांचा अॅप संकालित केला आहे किंवा नाही हे निर्धारित करू शकते."</string>
- <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"सिंक चालू आणि बंद करा टॉगल करा"</string>
+ <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"सिंक सुरू आणि बंद करा टॉगल करा"</string>
<string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"खात्यासाठी सिंक सेटिंग्ज सुधारित करण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांच्या अॅप चे सिंक सक्षम करण्यासाठी वापरले जाऊ शकते."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"सिंक आकडेवारी वाचा"</string>
<string name="permdesc_readSyncStats" msgid="3867809926567379434">"सिंक इव्हेंटचा इतिहास आणि किती डेटाचे सिंक केले आहे यासह, खात्याची सिंक स्थिती वाचण्यासाठी अॅप ला अनुमती देते."</string>
@@ -881,7 +881,7 @@
<string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"तुमचे वापरकर्तानाव किंवा पासवर्ड विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
<string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"तपासत आहे..."</string>
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"अनलॉक करा"</string>
- <string name="lockscreen_sound_on_label" msgid="1660281470535492430">"ध्वनी सुरु"</string>
+ <string name="lockscreen_sound_on_label" msgid="1660281470535492430">"ध्वनी सुरू"</string>
<string name="lockscreen_sound_off_label" msgid="2331496559245450053">"ध्वनी बंद"</string>
<string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"पॅटर्न सुरू केला"</string>
<string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"पॅटर्न साफ केला"</string>
@@ -988,8 +988,8 @@
<string name="searchview_description_submit" msgid="6771060386117334686">"क्वेरी सबमिट करा"</string>
<string name="searchview_description_voice" msgid="42360159504884679">"व्हॉइस शोध"</string>
<string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"स्पर्श करून एक्सप्लोर करा सक्षम करायचे?"</string>
- <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा चालू असते, तेव्हा तुम्ही तुमच्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा टॅब्लेटसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
- <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा चालू असते, तेव्हा तुम्ही तुमच्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा फोनसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा सुरू असते, तेव्हा तुम्ही तुमच्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा टॅब्लेटसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा सुरू असते, तेव्हा तुम्ही तुमच्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा फोनसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
<string name="oneMonthDurationPast" msgid="4538030857114635777">"1 महिन्यापूर्वी"</string>
<string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"1 महिन्यापूर्वी"</string>
<plurals name="last_num_days" formatted="false" msgid="687443109145393632">
@@ -1203,7 +1203,7 @@
<string name="heavy_weight_notification" msgid="8382784283600329576">"रन होणारे <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="heavy_weight_notification_detail" msgid="6802247239468404078">"गेमवर परत जाण्यासाठी टॅप करा"</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"गेम निवडा"</string>
- <string name="heavy_weight_switcher_text" msgid="6814316627367160126">"अधिक चांगल्या कामगिरीसाठी, एकावेळी यापैकी केवळ एक गेम चालू ठेवता येईल."</string>
+ <string name="heavy_weight_switcher_text" msgid="6814316627367160126">"अधिक चांगल्या कामगिरीसाठी, एकावेळी यापैकी केवळ एक गेम सुरू ठेवता येईल."</string>
<string name="old_app_action" msgid="725331621042848590">"<xliff:g id="OLD_APP">%1$s</xliff:g> वर परत जा"</string>
<string name="new_app_action" msgid="547772182913269801">"<xliff:g id="NEW_APP">%1$s</xliff:g> उघडा"</string>
<string name="new_app_description" msgid="1958903080400806644">"<xliff:g id="OLD_APP">%1$s</xliff:g> सेव्ह न करता बंद होईल"</string>
@@ -1262,7 +1262,7 @@
<string name="decline" msgid="6490507610282145874">"नकार द्या"</string>
<string name="select_character" msgid="3352797107930786979">"वर्ण घाला"</string>
<string name="sms_control_title" msgid="4748684259903148341">"SMS मेसेज पाठवत आहे"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> मोठ्या संख्येने SMS मेसेज पाठवत आहे. तुम्ही या अॅप ला मेसेज पाठविणे सुरु ठेवण्याची अनुमती देऊ इच्छिता?"</string>
+ <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> मोठ्या संख्येने SMS मेसेज पाठवत आहे. तुम्ही या अॅप ला मेसेज पाठविणे सुरू ठेवण्याची अनुमती देऊ इच्छिता?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"अनुमती द्या"</string>
<string name="sms_control_no" msgid="4845717880040355570">"नकार द्या"</string>
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> हा <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>वर एक मेसेज पाठवू इच्छितो."</string>
@@ -1297,10 +1297,10 @@
<string name="dlg_ok" msgid="5103447663504839312">"ठीक"</string>
<string name="usb_charging_notification_title" msgid="1674124518282666955">"हे डिव्हाइस USB ने चार्ज करत आहे"</string>
<string name="usb_supplying_notification_title" msgid="5378546632408101811">"USB ने चार्ज करायला ठेवलेले डिव्हाइस"</string>
- <string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB फाइल ट्रान्सफर चालू केले"</string>
- <string name="usb_ptp_notification_title" msgid="5043437571863443281">"USB मार्फत PTP चालू केले"</string>
- <string name="usb_tether_notification_title" msgid="8828527870612663771">"USB टेदरिंग चालू केले"</string>
- <string name="usb_midi_notification_title" msgid="7404506788950595557">"USB मार्फत MIDI चालू केले"</string>
+ <string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB फाइल ट्रान्सफर सुरू केले"</string>
+ <string name="usb_ptp_notification_title" msgid="5043437571863443281">"USB मार्फत PTP सुरू केले"</string>
+ <string name="usb_tether_notification_title" msgid="8828527870612663771">"USB टेदरिंग सुरू केले"</string>
+ <string name="usb_midi_notification_title" msgid="7404506788950595557">"USB मार्फत MIDI सुरू केले"</string>
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"USB अॅक्सेसरी कनेक्ट केली आहे"</string>
<string name="usb_notification_message" msgid="4715163067192110676">"अधिक पर्यायांसाठी टॅप करा."</string>
<string name="usb_power_notification_message" msgid="7284765627437897702">"चार्जर लावलेले डिव्हाइस. आणखी पर्यायांसाठी टॅप करा"</string>
@@ -1425,10 +1425,10 @@
<string name="vpn_title_long" msgid="6834144390504619998">"<xliff:g id="APP">%s</xliff:g> द्वारे VPN सक्रिय केले आहे"</string>
<string name="vpn_text" msgid="2275388920267251078">"नेटवर्क व्यवस्थापित करण्यासाठी टॅप करा."</string>
<string name="vpn_text_long" msgid="278540576806169831">"<xliff:g id="SESSION">%s</xliff:g> शी कनेक्ट केले. नेटवर्क व्यवस्थापित करण्यासाठी टॅप करा."</string>
- <string name="vpn_lockdown_connecting" msgid="6096725311950342607">"VPN कनेक्ट करणे नेहमी-चालू…"</string>
- <string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN कनेक्ट केलेले नेहमी-चालू"</string>
- <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"कायम चालू असलेल्या VPN मधून डिस्कनेक्ट केले"</string>
- <string name="vpn_lockdown_error" msgid="4453048646854247947">"कायम चालू असलेल्या VPN शी कनेक्ट करता आले नाही"</string>
+ <string name="vpn_lockdown_connecting" msgid="6096725311950342607">"VPN कनेक्ट करणे नेहमी-सुरू…"</string>
+ <string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN कनेक्ट केलेले नेहमी-सुरू"</string>
+ <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"कायम सुरू असलेल्या VPN मधून डिस्कनेक्ट केले"</string>
+ <string name="vpn_lockdown_error" msgid="4453048646854247947">"कायम सुरू असलेल्या VPN शी कनेक्ट करता आले नाही"</string>
<string name="vpn_lockdown_config" msgid="8331697329868252169">"नेटवर्क किंवा VPN सेटिंग्ज बदला"</string>
<string name="upload_file" msgid="8651942222301634271">"फाईल निवडा"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"फाईल निवडली नाही"</string>
@@ -1587,7 +1587,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"सिम पिन एंटर करा"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"पिन एंटर करा"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"पासवर्ड एंटर करा"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"सिम आता अक्षम केले आहे. सुरु ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"इच्छित पिन कोड एंटर करा"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"इच्छित पिन कोड ची पुष्टी करा"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"सिम कार्ड अनलॉक करत आहे…"</string>
@@ -1797,7 +1797,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"बॅटरीचे आयुष्य वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
<string name="battery_saver_description" msgid="8587408568232177204">"बॅटरीचे आयुष्य वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अॅप डेटा अॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर चालू करायचे?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर सुरू करायचे?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सुरू करा"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="other">%1$d मिनिटांसाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
@@ -1890,7 +1890,7 @@
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"अॅप उघडा"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल सुरू ठेवायची?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"तुमची कार्य अॅप्स, सूचना, डेटा आणि अन्य कार्य प्रोफाइल वैशिष्ट्ये सुरू केली जातील"</string>
- <string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करा"</string>
+ <string name="work_mode_turn_on" msgid="3662561662475962285">"सुरू करा"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पाहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string>
@@ -2025,7 +2025,7 @@
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> स्प्रेडशीट"</string>
<string name="mime_type_presentation" msgid="1145384236788242075">"सादरीकरण"</string>
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> सादरीकरण"</string>
- <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"विमान मोड दरम्यान ब्लूटूथ चालू राहील"</string>
+ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"विमान मोड दरम्यान ब्लूटूथ सुरू राहील"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"लोड होत आहे"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> फायली</item>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पॉवर डायलॉग"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करा"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ऑन-स्क्रीन ॲक्सेसिबिलिटी शॉर्टकट"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ऑन-स्क्रीन ॲक्सेसिबिलिटी शॉर्टकट निवडकर्ता"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"अॅक्सेसिबिलिटी शॉर्टकट"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> चा शीर्षक बार."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID अनलॉक करणे यशस्वी झाले."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI अनलॉक करणे यशस्वी झाले."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"नेटवर्क सबसेट सेवा पुरवठादार अनलॉक करणे यशस्वी झाले."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 23808b8..189821c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Kuasa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Pintasan Kebolehaksesan Pada Skrin"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Pemilih Pintasan Kebolehaksesan Pada Skrin"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pintasan Kebolehaksesan"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Buka kunci ICCID berjaya."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Buka kunci IMPI berjaya."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Buka kunci penyedia perkhidmatan subset rangkaian berjaya."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index f8e409d..80611df 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ပါဝါ ဒိုင်ယာလော့"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ဖန်သားပြင်အတွက် အများသုံးစွဲနိုင်မှုဖြတ်လမ်းလင့်ခ်"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ဖန်သားပြင်အတွက် အများသုံးစွဲနိုင်မှုဖြတ်လမ်းလင့်ခ် ရွေးချယ်စနစ်"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>-"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID လော့ခ်ဖွင့်၍ ရပါပြီ။"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI လော့ခ်ဖွင့်၍ ရပါပြီ။"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ကွန်ရက်ခွဲ ဝန်ဆောင်မှုပေးသူ လော့ခ်ဖွင့်၍ ရပါပြီ။"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f4b7ec3b..37127d0 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks for å slå av/på"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Tilgjengelighetssnarvei på skjermen"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Velger for tilgjengelighetssnarvei på skjermen"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Tilgjengelighetssnarvei"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID-opplåsingen er fullført."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI-opplåsingen er fullført."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Bestemte operatørlåser er blitt fjernet."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index ba599e84..d9e3b0c 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -191,7 +191,7 @@
<string name="device_ownership_relinquished" msgid="4080886992183195724">"व्यवस्थापकले यन्त्रलाई व्यक्तिगत प्रयोगका लागि अस्वीकार गर्नुभयो"</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"यन्त्र व्यवस्थित गरिएको छ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"तपाईंको संगठनले यस यन्त्रको व्यवस्थापन गर्दछ र नेटवर्क ट्राफिकको अनुगमन गर्न सक्छ। विवरणहरूका लागि ट्याप गर्नुहोस्।"</string>
- <string name="location_changed_notification_title" msgid="3620158742816699316">"अनुप्रयोगहरूले तपाईंको स्थान प्रयोग गर्न सक्छन्"</string>
+ <string name="location_changed_notification_title" msgid="3620158742816699316">"एपहरूले तपाईंको स्थान प्रयोग गर्न सक्छन्"</string>
<string name="location_changed_notification_text" msgid="7158423339982706912">"थप जानकारी प्राप्त गर्न आफ्ना IT प्रशासकसँग सम्पर्क गर्नुहोस्"</string>
<string name="country_detector" msgid="7023275114706088854">"देश पत्ता लगाउने सुविधा"</string>
<string name="location_service" msgid="2439187616018455546">"स्थानसम्बन्धी सेवा"</string>
@@ -284,9 +284,9 @@
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"खुद्रा बिक्री सम्बन्धी डेमो"</string>
<string name="notification_channel_usb" msgid="1528280969406244896">"USB जडान"</string>
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"एप चलिरहेको छ"</string>
- <string name="notification_channel_foreground_service" msgid="7102189948158885178">"अनुप्रयोगहरूले ब्याट्री खपत गर्दै छन्"</string>
+ <string name="notification_channel_foreground_service" msgid="7102189948158885178">"एपहरूले ब्याट्री खपत गर्दै छन्"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले ब्याट्री प्रयोग गर्दै छ"</string>
- <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> अनुप्रयोगहरूले ब्याट्री प्रयोग गर्दै छन्"</string>
+ <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> एपहरूले ब्याट्री प्रयोग गर्दै छन्"</string>
<string name="foreground_service_tap_for_details" msgid="9078123626015586751">"ब्याट्री र डेटाका प्रयोग सम्बन्धी विवरणहरूका लागि ट्याप गर्नुहोस्"</string>
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="8974401416068943888">"सुरक्षित मोड"</string>
@@ -330,47 +330,47 @@
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"स्क्रिनसट लिनुहोस्"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"डिस्प्लेको स्क्रिनसट लिन सकिन्छ।"</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"स्थिति पट्टिलाई अक्षम वा संशोधित गर्नुहोस्"</string>
- <string name="permdesc_statusBar" msgid="5809162768651019642">"स्थिति पट्टि असक्षम पार्न वा प्रणाली आइकनहरू थप्न र हटाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_statusBar" msgid="5809162768651019642">"स्थिति पट्टि असक्षम पार्न वा प्रणाली आइकनहरू थप्न र हटाउन एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"स्टाटस बार हुन दिनुहोस्"</string>
- <string name="permdesc_statusBarService" msgid="6652917399085712557">"अनुप्रयोगलाई स्थिति पट्टि हुन अनुमति दिन्छ।"</string>
+ <string name="permdesc_statusBarService" msgid="6652917399085712557">"एपलाई स्थिति पट्टि हुन अनुमति दिन्छ।"</string>
<string name="permlab_expandStatusBar" msgid="1184232794782141698">"स्थिति पट्टिलाई विस्तृत/सङ्कुचित गर्नुहोस्"</string>
- <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"अनुप्रयोगलाई स्थिति पट्टि विस्तार वा संकुचन गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"एपलाई स्थिति पट्टि विस्तार वा संकुचन गर्न अनुमति दिन्छ।"</string>
<string name="permlab_install_shortcut" msgid="7451554307502256221">"सर्टकट स्थापना गर्नुहोस्"</string>
- <string name="permdesc_install_shortcut" msgid="4476328467240212503">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिन्छ।"</string>
+ <string name="permdesc_install_shortcut" msgid="4476328467240212503">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिन्छ।"</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"सर्टकटहरूको स्थापन रद्द गर्नुहोस्"</string>
- <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा हटाउनको लागि अनुमति दिन्छ।"</string>
+ <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा हटाउनको लागि अनुमति दिन्छ।"</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"बहिर्गमन कलहरूलाई अर्को मार्ग दिनुहोस्"</string>
- <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"अनुप्रयोगलाई अन्य नम्बरमा कल पुर्ननिर्देश वा समग्र कल परित्याग विकल्प सहित बहिर्गमन कल समयमा डायल गर्दाको नम्बर हेर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"एपलाई अन्य नम्बरमा कल पुर्ननिर्देश वा समग्र कल परित्याग विकल्प सहित बहिर्गमन कल समयमा डायल गर्दाको नम्बर हेर्न अनुमति दिन्छ।"</string>
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"फोन कलहरूको जवाफ दिनुहोस्"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"अनुप्रयोगलाई आगमन फोन कलको जवाफ दिन अनुमति दिन्छ।"</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"एपलाई आगमन फोन कलको जवाफ दिन अनुमति दिन्छ।"</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"पाठ सन्देशहरू (SMS) प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_receiveSms" msgid="1797345626687832285">"अनुप्रयोगलाई SMS सन्देशहरू प्राप्त गर्न र प्रक्रिया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको सन्देशहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
+ <string name="permdesc_receiveSms" msgid="1797345626687832285">"एपलाई SMS सन्देशहरू प्राप्त गर्न र प्रक्रिया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको सन्देशहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"पाठ सन्देश (MMS) प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_receiveMms" msgid="958102423732219710">"अनुप्रयोगलाई MMS सन्देशहरू प्राप्त गर्न र प्रकृया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको सन्देशहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
+ <string name="permdesc_receiveMms" msgid="958102423732219710">"एपलाई MMS सन्देशहरू प्राप्त गर्न र प्रकृया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको सन्देशहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
<string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"मोबाइल प्रसारणसम्बन्धी सन्देशहरू फर्वार्ड गर्नुहोस्"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"मोबाइल प्रसारणसम्बन्धी सन्देशहरू प्राप्त हुनासाथै तिनीहरूलाई फर्वार्ड गर्नका लागि यसले अनुप्रयोगलाई मोबाइल प्रसारण मोड्युलमा जोडिने अनुमति दिन्छ। तपाईंलाई कतिपय स्थानमा आपत्कालीन अवस्थाका बारेमा जानकारी दिनका लागि मोबाइल प्रसारणसम्बन्धी अलर्टहरू पठाइन्छ। हानिकारक अनुप्रयोगहरूले आपत्कालीन मोबाइल प्रसारण प्राप्त हुँदा तपाईंको यन्त्रलाई कार्य सम्पादन गर्ने वा सञ्चालित हुने क्रममा हस्तक्षेप गर्न सक्छन्।"</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"मोबाइल प्रसारणसम्बन्धी सन्देशहरू प्राप्त हुनासाथै तिनीहरूलाई फर्वार्ड गर्नका लागि यसले एपलाई मोबाइल प्रसारण मोड्युलमा जोडिने अनुमति दिन्छ। तपाईंलाई कतिपय स्थानमा आपत्कालीन अवस्थाका बारेमा जानकारी दिनका लागि मोबाइल प्रसारणसम्बन्धी अलर्टहरू पठाइन्छ। हानिकारक एपहरूले आपत्कालीन मोबाइल प्रसारण प्राप्त हुँदा तपाईंको यन्त्रलाई कार्य सम्पादन गर्ने वा सञ्चालित हुने क्रममा हस्तक्षेप गर्न सक्छन्।"</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारित सन्देशहरू पढ्नुहोस्"</string>
- <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"तपाईंको उपकरणद्वारा प्राप्त सेल प्रसारण सन्देशहरू अनुप्रयोगलाई पढ्न अनुमति दिन्छ। सेल प्रसारण चेतावनीहरू केही स्थानहरूमा तपाईंलाई आपतकालीन गतिविधिहरूको बारेमा सचेत गराउन गरिएका छन्। खराब अनुप्रयोगहरूले एउटा आपतकालीन सेल प्रसारण प्राप्त गर्दछ जब तपाईंको उपकरणको प्रदर्शन वा अपरेशनको साथ हस्तक्षेप गर्न सक्दछन्।"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"तपाईंको उपकरणद्वारा प्राप्त सेल प्रसारण सन्देशहरू एपलाई पढ्न अनुमति दिन्छ। सेल प्रसारण चेतावनीहरू केही स्थानहरूमा तपाईंलाई आपतकालीन गतिविधिहरूको बारेमा सचेत गराउन गरिएका छन्। खराब एपहरूले एउटा आपतकालीन सेल प्रसारण प्राप्त गर्दछ जब तपाईंको उपकरणको प्रदर्शन वा अपरेशनको साथ हस्तक्षेप गर्न सक्दछन्।"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्य बनाइका फिडहरू पढ्नुहोस्"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"अनुप्रयोगलाई अहिलेको समीकरण गरिएका सूचकहरू बारे विवरणहरू लिने अनुमति दिन्छ।"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"एपलाई अहिलेको समीकरण गरिएका सूचकहरू बारे विवरणहरू लिने अनुमति दिन्छ।"</string>
<string name="permlab_sendSms" msgid="7757368721742014252">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
- <string name="permdesc_sendSms" msgid="6757089798435130769">"अनुप्रयोगलाई SMS सन्देशहरू पठाउन अनुमति दिन्छ। यसले अप्रत्यासित चार्जहरूको परिणाम दिन सक्दछ। खराब अनुप्रयोगहरूले तपाईंको पुष्टि बिना सन्देशहरू पठाएर तपाईंको पैसा खर्च गराउन सक्दछ।"</string>
+ <string name="permdesc_sendSms" msgid="6757089798435130769">"एपलाई SMS सन्देशहरू पठाउन अनुमति दिन्छ। यसले अप्रत्यासित चार्जहरूको परिणाम दिन सक्दछ। खराब एपहरूले तपाईंको पुष्टि बिना सन्देशहरू पठाएर तपाईंको पैसा खर्च गराउन सक्दछ।"</string>
<string name="permlab_readSms" msgid="5164176626258800297">"तपाईंका पाठ सन्देशहरू (SMS वा MMS) पढ्नुहोस्"</string>
<string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"यस अनुप्रयोगले तपाईंको ट्याब्लेटमा भण्डारण गरिएका सबै SMS (पाठ) सन्देशहरू पढ्न सक्छ।"</string>
<string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"यस अनुप्रयोगले तपाईंको Android TV यन्त्रमा भण्डार गरिएका सबै SMS.(पाठ) सन्देशहरू पढ्न सक्छ।"</string>
<string name="permdesc_readSms" product="default" msgid="774753371111699782">"यस अनुप्रयोगले तपाईंको फोनमा भण्डारण गरिएका सबै SMS (पाठ) सन्देशहरू पढ्न सक्छ।"</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"पाठ सन्देशहरू (WAP) प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP सन्देशहरू प्राप्त गर्न र प्रशोधन गर्न अनुप्रयोगलाई अनुमति दिन्छ। यो अनुमतिमा मोनिटर गर्ने वा तपाईँलाई पठाइएका सन्देशहरू तपाईँलाई नदेखाई मेट्ने क्षमता समावेश हुन्छ।"</string>
+ <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP सन्देशहरू प्राप्त गर्न र प्रशोधन गर्न एपलाई अनुमति दिन्छ। यो अनुमतिमा मोनिटर गर्ने वा तपाईँलाई पठाइएका सन्देशहरू तपाईँलाई नदेखाई मेट्ने क्षमता समावेश हुन्छ।"</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"चलिरहेका एपहरू पुनःबहाली गर्नुहोस्"</string>
- <string name="permdesc_getTasks" msgid="7388138607018233726">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न अनुप्रयोगलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका अनुप्रयोगहरूको बारेमा सूचना पत्ता लगाउन अनुप्रयोगलाई अनुमति दिन सक्छ।"</string>
+ <string name="permdesc_getTasks" msgid="7388138607018233726">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न एपलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका अनुप्रयोगहरूको बारेमा सूचना पत्ता लगाउन एपलाई अनुमति दिन सक्छ।"</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"प्रोफाइल र यन्त्र मालिकहरूको व्यवस्थापन गराउनुहोस्"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"अनुप्रयोगहरूलाई प्रोफाइल र यन्त्र मालिकहरू सेट गर्न अनुमति दिनुहोस्।"</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"चलिरहेका अनुप्रयोगहरूलाई पुनःक्रम गराउनुहोस्"</string>
- <string name="permdesc_reorderTasks" msgid="8796089937352344183">"कामहरूलाई अग्रभाग र पृष्ठभूमिमा सार्न अनुप्रयोगलाई अनुमति दिन्छ। अनुप्रयोगले यो तपाईँको इनपुट बिना नै गर्न सक्छ।"</string>
+ <string name="permdesc_reorderTasks" msgid="8796089937352344183">"कामहरूलाई अग्रभाग र पृष्ठभूमिमा सार्न एपलाई अनुमति दिन्छ। अनुप्रयोगले यो तपाईँको इनपुट बिना नै गर्न सक्छ।"</string>
<string name="permlab_enableCarMode" msgid="893019409519325311">"कार मोड सक्षम गर्नुहोस्"</string>
- <string name="permdesc_enableCarMode" msgid="56419168820473508">"कार मोडलाई सक्षम पार्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_enableCarMode" msgid="56419168820473508">"कार मोडलाई सक्षम पार्न एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"एपहरू बन्द गर्नुहोस्"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"अनुप्रयोगलाई अन्य अनुप्रयोगहरूको पृष्ठभूमि प्रक्रियाहरू बन्द गर्न अनुमति दिन्छ। यसले अन्य अनुप्रयोगहरूलाई चल्नबाट रोक्न सक्दछ।"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"एपलाई अन्य अनुप्रयोगहरूको पृष्ठभूमि प्रक्रियाहरू बन्द गर्न अनुमति दिन्छ। यसले अन्य अनुप्रयोगहरूलाई चल्नबाट रोक्न सक्दछ।"</string>
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"यो एप अन्य एपहरूमाथि देखा पर्न सक्छ"</string>
<string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"यो एप अन्य एपहरूमाथि वा स्क्रिनका अन्य भागहरूमा देखा पर्न सक्छ। यसले एपको सामान्य प्रयोगमा अवरोध पुर्याउन सक्छ र अन्य एपहरू देखा पर्ने तरिकालाई परिवर्तन गर्न सक्छ।"</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"पृष्ठभूमिमा चलाउनुहोस्"</string>
@@ -378,37 +378,37 @@
<string name="permlab_useDataInBackground" msgid="783415807623038947">"पृष्ठभूमिमा डेटा प्रयोग गर्नुहोस्"</string>
<string name="permdesc_useDataInBackground" msgid="1230753883865891987">"यो अनुप्रयोगले पृष्ठभूमिमा डेटा प्रयोग गर्नसक्छ। यसले गर्दा धेरै डेटा प्रयोग हुनसक्छ।"</string>
<string name="permlab_persistentActivity" msgid="464970041740567970">"एपहरू जहिले पनि चल्ने बनाउनुहोस्"</string>
- <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"यसको आफ्नै मेमोरीमा दृढ भएकोको अंश बनाउनको लागि अनुप्रयोगलाई अनुमति दिन्छ। ट्याब्लेटलाई ढिलो गराउँदै गरेका अन्य अनुप्रयोगहरूलाई सीमित मात्रामा यसले मेमोरी उपलब्ध गराउन सक्छ।"</string>
- <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"अनुप्रयोगलाई आफ्ना केही अंशहरू मेमोरीमा स्थायी रूपमा राख्ने अनुमति दिन्छ। यसले गर्दा अन्य अनुप्रयोगहरूका लागि मेमोरीको अभाव हुन सक्ने भएकाले तपाईंको Android TV यन्त्र सुस्त हुन सक्छ।"</string>
- <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"अनुप्रयोगलाई मेमोरीमा आफैंको निरन्तरको अंश बनाउन अनुमति दिन्छ। यसले फोनलाई ढिला बनाएर अन्य अनुप्रयोगहरूमा मेमोरी SIMित गर्न सक्दछन्।"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"यसको आफ्नै मेमोरीमा दृढ भएकोको अंश बनाउनको लागि एपलाई अनुमति दिन्छ। ट्याब्लेटलाई ढिलो गराउँदै गरेका अन्य अनुप्रयोगहरूलाई सीमित मात्रामा यसले मेमोरी उपलब्ध गराउन सक्छ।"</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"एपलाई आफ्ना केही अंशहरू मेमोरीमा स्थायी रूपमा राख्ने अनुमति दिन्छ। यसले गर्दा अन्य अनुप्रयोगहरूका लागि मेमोरीको अभाव हुन सक्ने भएकाले तपाईंको Android TV यन्त्र सुस्त हुन सक्छ।"</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"एपलाई मेमोरीमा आफैंको निरन्तरको अंश बनाउन अनुमति दिन्छ। यसले फोनलाई ढिला बनाएर अन्य एपहरूमा मेमोरी SIMित गर्न सक्दछन्।"</string>
<string name="permlab_foregroundService" msgid="1768855976818467491">"अग्रभूमिको सेवा सञ्चालन गर्नुहोस्"</string>
- <string name="permdesc_foregroundService" msgid="8720071450020922795">"अनुप्रयोगलाई अग्रभूमिका सेवाहरू प्रयोग गर्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_foregroundService" msgid="8720071450020922795">"एपलाई अग्रभूमिका सेवाहरू प्रयोग गर्ने अनुमति दिन्छ।"</string>
<string name="permlab_getPackageSize" msgid="375391550792886641">"एप भण्डारण ठाउँको मापन गर्नुहोस्"</string>
- <string name="permdesc_getPackageSize" msgid="742743530909966782">"अनुप्रयोगलाई यसको कोड, डेटा, र क्यास आकारहरू पुनःप्राप्त गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_getPackageSize" msgid="742743530909966782">"एपलाई यसको कोड, डेटा, र क्यास आकारहरू पुनःप्राप्त गर्न अनुमति दिन्छ।"</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"प्रणाली सेटिङहरू परिमार्जन गर्नुहोस्"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"प्रणालीका सेटिङ डेटालाई परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। खराब अनुप्रयोगहरूले सायद तपाईँको प्रणालीको कन्फिगरेसनलाई क्षति पुर्याउन सक्छन्।"</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"प्रणालीका सेटिङ डेटालाई परिवर्तन गर्नको लागि एपलाई अनुमति दिन्छ। खराब एपहरूले सायद तपाईँको प्रणालीको कन्फिगरेसनलाई क्षति पुर्याउन सक्छन्।"</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"स्टार्टअपमा चलाउनुहोस्"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"आनुप्रयोगलाई प्रणाली बुट प्रक्रिया पूर्ण हुने बितिकै आफैलाई सुरु गर्ने अनुमति दिन्छ। यसले ट्याब्लेट सुरु गर्नमा ढिला गर्न सक्दछ र अनुप्रयोगलाई समग्रमा ट्याब्लेट सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"आनुप्रयोगलाई प्रणाली बुट प्रक्रिया पूर्ण हुने बितिकै आफैलाई सुरु गर्ने अनुमति दिन्छ। यसले ट्याब्लेट सुरु गर्नमा ढिला गर्न सक्दछ र एपलाई समग्रमा ट्याब्लेट सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"एपलाई प्रणाली बुट हुने बित्तिकै स्वत: सुरु हुने अनुमति दिन्छ। यसो गर्दा एप सधैँ चलिरहने भएकाले तपाईंको Android TV यन्त्र सुरु हुन बढी समय लाग्नुका साथै यन्त्रको समग्र कार्यसम्पादन सुस्त हुन सक्छ।"</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"अनुप्रयोगलाई प्रणाली बुट गरी सकेपछि जति सक्दो चाँडो आफैंमा सुरु गर्न अनुमति दिन्छ। यसले फोन सुरु गर्नमा ढिला गर्न सक्दछ र अनप्रयोगलाई समग्रमा फोन सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"एपलाई प्रणाली बुट गरी सकेपछि जति सक्दो चाँडो आफैंमा सुरु गर्न अनुमति दिन्छ। यसले फोन सुरु गर्नमा ढिला गर्न सक्दछ र अनप्रयोगलाई समग्रमा फोन सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
<string name="permlab_broadcastSticky" msgid="4552241916400572230">"स्टिकि प्रसारण पठाउनुहोस्"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"औपचारिक प्रसारणलाई पठाउनको लागि एउटा अनुप्रयोगलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले ट्याब्लेटलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
- <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"अनुप्रयोगलाई प्रसारण समाप्त भइसकेपछि पनि रहिरहने स्टिकी प्रसारणहरू पठाउने अनुमति दिन्छ। यो सुविधाको अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग हुने भएकाले तपाईंको Android TV यन्त्र सुस्त वा अस्थिर हुन सक्छ।"</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"औपचारिक प्रसारणलाई पठाउनको लागि एक अनुप्रयोगलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले फोनलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"औपचारिक प्रसारणलाई पठाउनको लागि एउटा एपलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले ट्याब्लेटलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"एपलाई प्रसारण समाप्त भइसकेपछि पनि रहिरहने स्टिकी प्रसारणहरू पठाउने अनुमति दिन्छ। यो सुविधाको अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग हुने भएकाले तपाईंको Android TV यन्त्र सुस्त वा अस्थिर हुन सक्छ।"</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"औपचारिक प्रसारणलाई पठाउनको लागि एक एपलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले फोनलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
<string name="permlab_readContacts" msgid="8776395111787429099">"तपाईँका सम्पर्कहरू पढ्नुहोस्"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"अनुप्रयोगलाई तपाईंको ट्याब्लेटमा भण्डार गरिएका सम्पर्क ठेगानाहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। अनुप्रयोगहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको ट्याब्लेटमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका अनुप्रयोगहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक अनुप्रयोगहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
- <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा पढ्न अनुमति दिन्छ। अनुप्रयोगहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको Android TV यन्त्रमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका अनुप्रयोगहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक अनुप्रयोगहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
- <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"अनुप्रयोगलाई तपाईंको फोनमा भण्डार गरिएका सम्पर्क ठेगानाहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। अनुप्रयोगहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको फोनमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका अनुप्रयोगहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक अनुप्रयोगहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"एपलाई तपाईंको ट्याब्लेटमा भण्डार गरिएका सम्पर्क ठेगानाहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको ट्याब्लेटमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
+ <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"एपलाई तपाईंको Android TV यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा पढ्न अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको Android TV यन्त्रमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
+ <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"एपलाई तपाईंको फोनमा भण्डार गरिएका सम्पर्क ठेगानाहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको फोनमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
<string name="permlab_writeContacts" msgid="8919430536404830430">"तपाईँका सम्पर्कहरू परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"अनुप्रयोगलाई तपाईंको ट्याब्लेटमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले अनुप्रयोगलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
- <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले अनुप्रयोगलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
- <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"अनुप्रयोगलाई तपाईंको फोनमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले अनुप्रयोगलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"एपलाई तपाईंको ट्याब्लेटमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"एपलाई तपाईंको Android TV यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
+ <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"एपलाई तपाईंको फोनमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
<string name="permlab_readCallLog" msgid="1739990210293505948">"कल लग पढ्नुहोस्"</string>
<string name="permdesc_readCallLog" msgid="8964770895425873433">"यस अनुप्रयोगले तपाईंको फोन सम्पर्कको इतिहास पढ्न सक्छ।"</string>
<string name="permlab_writeCallLog" msgid="670292975137658895">"कल लग लेख्नुहोस्"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"आगमन तथा बहर्गमन डेटासहित तपाईँको ट्याब्लेटको कल लगको परिमार्जन गर्न अनुप्रयोगलाई अनुमति दिन्छ। खराब अनुप्रयोगहरूले यसलाई तपाईँको कल लग परिमार्जन गर्न वा मेटाउन प्रयोग गर्न सक्छन्।"</string>
- <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रको आगमन र बहिर्गमन कलसम्बन्धी डेटासहित कल लग परिमार्जन गर्ने अनुमति दिन्छ। हानिकारक अनुप्रयोगहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्छन्।"</string>
- <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"अनुप्रयोगलाई तपाईंको फोनको आउने र बाहिर जाने कलहरूको बारेको डेटा सहित कल लग परिमार्जन गर्न अनुमति दिन्छ। खराब अनुप्रयोगहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्दछ।"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"आगमन तथा बहर्गमन डेटासहित तपाईँको ट्याब्लेटको कल लगको परिमार्जन गर्न एपलाई अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईँको कल लग परिमार्जन गर्न वा मेटाउन प्रयोग गर्न सक्छन्।"</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"एपलाई तपाईंको Android TV यन्त्रको आगमन र बहिर्गमन कलसम्बन्धी डेटासहित कल लग परिमार्जन गर्ने अनुमति दिन्छ। हानिकारक एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्छन्।"</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"एपलाई तपाईंको फोनको आउने र बाहिर जाने कलहरूको बारेको डेटा सहित कल लग परिमार्जन गर्न अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्दछ।"</string>
<string name="permlab_bodySensors" msgid="3411035315357380862">"शरीरका सेन्सरहरूमा पहुँच गराउनुहोस् (जस्तै हृदय धड्कन निगरानीहरू)"</string>
<string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"तपाईँको हृदय गति जस्तो सेंसर बाट डेटा पहुँचको लागि एप अनुमति दिन्छ जसले तपाईँको भौतिक अवस्था अनुगमन गर्छ।"</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"पात्रोका कार्यक्रम र विवरणहरू पढ्ने"</string>
@@ -420,7 +420,7 @@
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"यस अनुप्रयोगले तपाईंको Android TV यन्त्रमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरूले पठाएको जस्तै देखिने सन्देशहरू पठाउन वा कार्यक्रमका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
<string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"यस अनुप्रयोगले तपाईंको फोनमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने सन्देशहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"अधिक स्थान प्रदायक आदेशहरू पहुँच गर्नुहोस्"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"अनुप्रयोगलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो अनुप्रयोगलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"एपलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो एपलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"अग्रभूमिमा मात्र सटीक स्थानमाथि पहुँच राख्नुहोस्"</string>
<string name="permdesc_accessFineLocation" msgid="6732174080240016335">"यो एप चलाएका बेला यसले स्थानसम्बन्धी सेवाहरूबाट तपाईंको स्थानको सटीक जानकारी प्राप्त गर्न सक्छ। तपाईंको यन्त्रमा स्थानसम्बन्धी सेवाहरू सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ। यसले ब्याट्रीको उपयोग बढाउन सक्छ।"</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"अग्रभागमा मात्र अनुमानित स्थानमाथि पहुँच राख्नुहोस्"</string>
@@ -428,11 +428,11 @@
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"पृष्ठभूमिमा स्थानसम्बन्धी पहुँच"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"यो एपले जुनसुकै बेला (एप नचलाएका बेलामा पनि) स्थानमाथि पहुँच राख्न सक्छ।"</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"तपाईँका अडियो सेटिङहरू परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"अनुप्रयोगलाई ग्लोबल अडियो सेटिङहरू परिमार्जन गर्न अनुमति दिन्छ, जस्तै भोल्युम र आउटपुटको लागि कुन स्पिकर प्रयोग गर्ने।"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"एपलाई ग्लोबल अडियो सेटिङहरू परिमार्जन गर्न अनुमति दिन्छ, जस्तै भोल्युम र आउटपुटको लागि कुन स्पिकर प्रयोग गर्ने।"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"अडियो रेकर्ड गर्नुहोस्"</string>
<string name="permdesc_recordAudio" msgid="3976213377904701093">"यस अनुप्रयोगले जुनसुकै समय माइक्रोफोनको प्रयोग गरी अडियो रेकर्ड गर्न सक्छ।"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM मा आदेशहरू पठाउन दिनुहोस्"</string>
- <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन अनुप्रयोगलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string>
+ <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन एपलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक गतिविधि पहिचान गर्नुहोस्"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"यो अनुप्रयोगले तपाईंको शारीरिक गतिविधिको पहिचान गर्न सक्छ।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"तस्बिरहरू र भिडियोहरू लिनुहोस्।"</string>
@@ -442,100 +442,100 @@
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"कुनै एप वा सेवालाई खोलिँदै वा बन्द गरिँदै गरेका क्यामेरा यन्त्रहरूका बारेमा कलब्याक प्राप्त गर्ने अनुमति दिनुहोस्।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"कुनै क्यामेरा यन्त्र खोलिँदा (कुन अनुप्रयोगले खोलेको भन्ने बारेमा) वा बन्द गरिँदा यो अनुप्रयोगले कलब्याक प्राप्त गर्न सक्छ।"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"कम्पन नियन्त्रण गर्नुहोस्"</string>
- <string name="permdesc_vibrate" msgid="8733343234582083721">"अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
- <string name="permdesc_vibrator_state" msgid="7050024956594170724">"यो अनुप्रयोगलाई कम्पनको स्थितिमाथि पहुँच राख्न दिनुहोस्।"</string>
+ <string name="permdesc_vibrate" msgid="8733343234582083721">"एपलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_vibrator_state" msgid="7050024956594170724">"यो एपलाई कम्पनको स्थितिमाथि पहुँच राख्न दिनुहोस्।"</string>
<string name="permlab_callPhone" msgid="1798582257194643320">"फोन नम्बरहरूमा सीधै कल गर्नुहोस्"</string>
- <string name="permdesc_callPhone" msgid="5439809516131609109">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले अनुप्रयोगलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब अनुप्रयोगहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string>
+ <string name="permdesc_callPhone" msgid="5439809516131609109">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न एपलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले एपलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब एपहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string>
<string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS कल सेवा पहुँच गर्नुहोस्"</string>
- <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"तपाईँको हस्तक्षेप बिना नै कल गर्न IMS सेवा प्रयोग गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"तपाईँको हस्तक्षेप बिना नै कल गर्न IMS सेवा प्रयोग गर्न एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"फोन स्थिति र पहिचान पढ्नुहोस्"</string>
- <string name="permdesc_readPhoneState" msgid="7229063553502788058">"उपकरणको फोन विशेषताहरूको पहुँच गर्न अनुप्रयोगलाई अनुमति दिन्छ। यस अनुमतिले फोन नम्बर र उपकरणको IDs, कल सक्षम छ कि छैन र कलद्वारा जोडिएको टाढाको नम्बर निर्धारण गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_readPhoneState" msgid="7229063553502788058">"उपकरणको फोन विशेषताहरूको पहुँच गर्न एपलाई अनुमति दिन्छ। यस अनुमतिले फोन नम्बर र उपकरणको IDs, कल सक्षम छ कि छैन र कलद्वारा जोडिएको टाढाको नम्बर निर्धारण गर्न अनुमति दिन्छ।"</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"प्रणाली मार्फत कल गर्न दिनुहोस्"</string>
- <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"कल गर्दाको अनुभवलाई सुधार्न यस अनुप्रयोगलाई प्रणाली मार्फत कलहरू गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"कल गर्दाको अनुभवलाई सुधार्न यस एपलाई प्रणाली मार्फत कलहरू गर्न अनुमति दिन्छ।"</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"प्रणालीमार्फत कलहरू हेर्नुका साथै तिनीहरूलाई नियन्त्रण गर्नुहोस्।"</string>
- <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"अनुप्रयोगलाई यन्त्रमा जारी रहेका कलहरू हेर्नुका साथै तिनीहरूलाई गर्ने अनुमति दिनुहोस्। यसमा गरिएका कलहरूको सङ्ख्या र कलहरूको अवस्था जस्ता जानकारी समावेश हुन्छन्।"</string>
+ <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"एपलाई यन्त्रमा जारी रहेका कलहरू हेर्नुका साथै तिनीहरूलाई गर्ने अनुमति दिनुहोस्। यसमा गरिएका कलहरूको सङ्ख्या र कलहरूको अवस्था जस्ता जानकारी समावेश हुन्छन्।"</string>
<string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"अडियो रेकर्ड गर्ने कार्यमा लगाइएका प्रतिबन्धहरूबाट छुट दिनुहोस्"</string>
- <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"यो अनुप्रयोगलाई अडियो रेकर्ड गर्ने कार्यमा लगाइएका प्रतिबन्धहरूबाट छुट दिनुहोस्।"</string>
+ <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"यो एपलाई अडियो रेकर्ड गर्ने कार्यमा लगाइएका प्रतिबन्धहरूबाट छुट दिनुहोस्।"</string>
<string name="permlab_acceptHandover" msgid="2925523073573116523">"अर्को अनुप्रयोगमा सुरु गरिएको कल जारी राख्नुहोस्"</string>
- <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"यस अनुप्रयोगलाई अर्को अनुप्रयोगमा सुरु गरिएको कल जारी राख्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"यस एपलाई अर्को अनुप्रयोगमा सुरु गरिएको कल जारी राख्ने अनुमति दिन्छ।"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"फोन नम्बरहरू पढ्ने"</string>
- <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"उक्त अनुप्रयोगलाई यस यन्त्रको फोन नम्बरहरूमाथि पहुँच राख्न दिनुहोस्।"</string>
+ <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"उक्त एपलाई यस यन्त्रको फोन नम्बरहरूमाथि पहुँच राख्न दिनुहोस्।"</string>
<string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"कारको स्क्रिन सक्रिय राख्नुहोस्"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ट्याब्लेटलाई निन्द्रामा जानबाट रोक्नुहोस्"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"आफ्नो Android TV यन्त्रलाई शयन अवस्थामा जान नदिनुहोस्"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"फोनलाई निदाउनबाट रोक्नुहोस्"</string>
- <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"यो अनुमतिले यस अनुप्रयोगलाई कारको स्क्रिन सक्रिय राख्न दिन्छ।"</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ट्याब्लेटलाई निस्क्रिय हुनबाट रोक्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
- <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रलाई शयन अवस्थामा जानबाट रोक्ने अनुमति दिन्छ।"</string>
- <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"फोनलाई निस्क्रिय हुनबाट रोक्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"यो अनुमतिले यस एपलाई कारको स्क्रिन सक्रिय राख्न दिन्छ।"</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ट्याब्लेटलाई निस्क्रिय हुनबाट रोक्नको लागि एपलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"एपलाई तपाईंको Android TV यन्त्रलाई शयन अवस्थामा जानबाट रोक्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"फोनलाई निस्क्रिय हुनबाट रोक्नको लागि एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_transmitIr" msgid="8077196086358004010">"infrared ट्रान्समिट गर्नुहोस्"</string>
<string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"ट्याबलेटको infrared transmitter प्रयोगको लागि एप अनुमति दिन्छ।"</string>
- <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रको इन्फ्रारेड ट्रान्समिटर प्रयोग गर्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"एपलाई तपाईंको Android TV यन्त्रको इन्फ्रारेड ट्रान्समिटर प्रयोग गर्ने अनुमति दिन्छ।"</string>
<string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"फोनको infrared transmitter प्रयोगको लागि एप अनुमति दिन्छ।"</string>
<string name="permlab_setWallpaper" msgid="6959514622698794511">"वालपेपर सेट गर्नुहोस्"</string>
- <string name="permdesc_setWallpaper" msgid="2973996714129021397">"अनुप्रयोगलाई प्रणाली वालपेपर सेट गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_setWallpaper" msgid="2973996714129021397">"एपलाई प्रणाली वालपेपर सेट गर्न अनुमति दिन्छ।"</string>
<string name="permlab_setWallpaperHints" msgid="1153485176642032714">"तपाईंको वालपेपर आकार समायोजन गर्नुहोस्"</string>
- <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"प्रणाली वालपेपरको आकार सङ्केतहरू मिलाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"प्रणाली वालपेपरको आकार सङ्केतहरू मिलाउन एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_setTimeZone" msgid="7922618798611542432">"समय क्षेत्र सेट गर्नुहोस्"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"अनुप्रयोगलाई ट्याब्लेटको समय क्षेत्र परिवर्तन गर्न अनुमति दिन्छ।"</string>
- <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रको समय क्षेत्र परिवर्तन गर्ने अनुमति दिन्छ।"</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"अनुप्रयोगलाई फोनको समय क्षेत्र परिवर्तन गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"एपलाई ट्याब्लेटको समय क्षेत्र परिवर्तन गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"एपलाई तपाईंको Android TV यन्त्रको समय क्षेत्र परिवर्तन गर्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"एपलाई फोनको समय क्षेत्र परिवर्तन गर्न अनुमति दिन्छ।"</string>
<string name="permlab_getAccounts" msgid="5304317160463582791">"उपकरणमा खाताहरू भेट्टाउनुहोस्"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"अनुप्रयोगलाई ट्याब्लेटद्वारा ज्ञात खाताहरूको सूची पाउन अनुमति दिन्छ। यसले अनुप्रयोगद्वारा तपाईंले स्थापित गर्नुभएको कुनै पनि खाताहरू समावेश गर्न सक्दछ।"</string>
- <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रले चिनेका खाताहरूको सूची प्राप्त गर्ने अनुमति दिन्छ। उक्त सूचीमा तपाईंले स्थापना गर्नुभएका अनुप्रयोगहरूले बनाएका कुनै पनि खाताहरू पर्न सक्छन्।"</string>
- <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"फोनलाई थाहा भएका खाताहरूको सूची प्राप्त गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले तपाईँले स्थापना गर्नु भएका अनुप्रयोगहरूबाट सृजित कुनै खाताहरू समावेश हुन सक्छ।"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"एपलाई ट्याब्लेटद्वारा ज्ञात खाताहरूको सूची पाउन अनुमति दिन्छ। यसले अनुप्रयोगद्वारा तपाईंले स्थापित गर्नुभएको कुनै पनि खाताहरू समावेश गर्न सक्दछ।"</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"एपलाई तपाईंको Android TV यन्त्रले चिनेका खाताहरूको सूची प्राप्त गर्ने अनुमति दिन्छ। उक्त सूचीमा तपाईंले स्थापना गर्नुभएका एपहरूले बनाएका कुनै पनि खाताहरू पर्न सक्छन्।"</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"फोनलाई थाहा भएका खाताहरूको सूची प्राप्त गर्न एपलाई अनुमति दिन्छ। यसले तपाईँले स्थापना गर्नु भएका अनुप्रयोगहरूबाट सृजित कुनै खाताहरू समावेश हुन सक्छ।"</string>
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"नेटवर्क जडानहरू हेर्नहोस्"</string>
- <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"अनुप्रयोगलाई नेटवर्क जडानहरू जस्तै कुन नेटवर्कहरू अवस्थित हुन्छन् र जडित छन् जसले हेर्नलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"एपलाई नेटवर्क जडानहरू जस्तै कुन नेटवर्कहरू अवस्थित हुन्छन् र जडित छन् जसले हेर्नलाई अनुमति दिन्छ।"</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"पूर्ण नेटवर्क पहुँच प्राप्त छ"</string>
- <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"नेटवर्क सकेटहरू सिर्जना गर्न र कस्टम नेटवर्क प्रोटोकल प्रयोग गर्न अनुप्रयोगलाई अनुमति दिन्छ। ब्राउजर र अन्य अनुप्रयोगहरूले इन्टरनेटमा डेटा पठाउने माध्यम प्रदान गर्छन्, त्यसैले इन्टरनेटमा डेटा पठाउन यो अनुमतिको आवश्यकता पर्दैन।"</string>
+ <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"नेटवर्क सकेटहरू सिर्जना गर्न र कस्टम नेटवर्क प्रोटोकल प्रयोग गर्न एपलाई अनुमति दिन्छ। ब्राउजर र अन्य एपहरूले इन्टरनेटमा डेटा पठाउने माध्यम प्रदान गर्छन्, त्यसैले इन्टरनेटमा डेटा पठाउन यो अनुमतिको आवश्यकता पर्दैन।"</string>
<string name="permlab_changeNetworkState" msgid="8945711637530425586">"नेटवर्क जडान परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_changeNetworkState" msgid="649341947816898736">"अनुप्रयोगलाई नेटवर्क जडानको स्थिति परिवर्तन गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_changeNetworkState" msgid="649341947816898736">"एपलाई नेटवर्क जडानको स्थिति परिवर्तन गर्न अनुमति दिन्छ।"</string>
<string name="permlab_changeTetherState" msgid="9079611809931863861">"टेथर्ड नेटवर्क जडान परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_changeTetherState" msgid="3025129606422533085">"टेदर गरेको नेटवर्क जडानको स्थिति बदल्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_changeTetherState" msgid="3025129606422533085">"टेदर गरेको नेटवर्क जडानको स्थिति बदल्न एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"Wi-Fi जडानहरू हेर्नुहोस्"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"अनुप्रयोगलाई Wi-Fi नेटवर्कको बारेमा जानकारी हेर्न अनुमति दिन्छ, जस्तै कि Wi-Fi सक्षम छ कि छैन र जडान गरिएको Wi-Fi उपकरणहरूको नाम।"</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"एपलाई Wi-Fi नेटवर्कको बारेमा जानकारी हेर्न अनुमति दिन्छ, जस्तै कि Wi-Fi सक्षम छ कि छैन र जडान गरिएको Wi-Fi उपकरणहरूको नाम।"</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"वाइ-फाइसँग जोड्नुहोस् वा छुटाउनुहोस्"</string>
- <string name="permdesc_changeWifiState" msgid="7170350070554505384">"अनुप्रयोगलाई Wi-Fi पहुँच बिन्दुबाट जडान गर्न र विच्छेदन गर्न र Wi-Fi नेटवर्कहरूको लागि उपकरण कन्फिगरेसनमा परिवर्तनहरू गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_changeWifiState" msgid="7170350070554505384">"एपलाई Wi-Fi पहुँच बिन्दुबाट जडान गर्न र विच्छेदन गर्न र Wi-Fi नेटवर्कहरूको लागि उपकरण कन्फिगरेसनमा परिवर्तनहरू गर्न अनुमति दिन्छ।"</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"Wi-Fi Multicast स्विकृतिलाई अनुमति दिनुहोस्"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"अनुप्रयोगलाई मल्टिकाष्ट ठेगानाहरू प्रयोग गरेर Wi-Fi नेटवर्कमा पठाइएको प्याकेटहरू प्राप्त गर्न अनुमति दिन्छ, केवल तपाईंको ट्याब्लेट मात्र होइन। यसले गैर-मल्टिकाष्ट मोड भन्दा बढी उर्जा प्रयोग गर्दछ।"</string>
- <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"अनुप्रयोगलाई मल्टिकास्ट ठेगानाहरू प्रयोग गरी तपाईंको Android TV यन्त्रमा मात्र नभई कुनै Wi-Fi नेटवर्कमा जोडिएका सबै यन्त्रहरूमा पठाइएका प्याकेटहरू प्राप्त गर्ने अनुमति दिन्छ। यसले गैर मल्टिकास्ट मोडभन्दा बढी पावर खपत गर्छ।"</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"तपाईँको फोन मात्र होइन, मल्टिकास्ट ठेगानाहरूको प्रयोग गरे Wi-Fi नेटवर्कका सबै उपकरणहरूमा पठाइएका प्याकेटहरू प्राप्त गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले गैर-मल्टिकास्ट मोडभन्दा बढी उर्जा प्रयोग गर्छ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"एपलाई मल्टिकाष्ट ठेगानाहरू प्रयोग गरेर Wi-Fi नेटवर्कमा पठाइएको प्याकेटहरू प्राप्त गर्न अनुमति दिन्छ, केवल तपाईंको ट्याब्लेट मात्र होइन। यसले गैर-मल्टिकाष्ट मोड भन्दा बढी उर्जा प्रयोग गर्दछ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"एपलाई मल्टिकास्ट ठेगानाहरू प्रयोग गरी तपाईंको Android TV यन्त्रमा मात्र नभई कुनै Wi-Fi नेटवर्कमा जोडिएका सबै यन्त्रहरूमा पठाइएका प्याकेटहरू प्राप्त गर्ने अनुमति दिन्छ। यसले गैर मल्टिकास्ट मोडभन्दा बढी पावर खपत गर्छ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"तपाईँको फोन मात्र होइन, मल्टिकास्ट ठेगानाहरूको प्रयोग गरे Wi-Fi नेटवर्कका सबै उपकरणहरूमा पठाइएका प्याकेटहरू प्राप्त गर्न एपलाई अनुमति दिन्छ। यसले गैर-मल्टिकास्ट मोडभन्दा बढी उर्जा प्रयोग गर्छ।"</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ब्लुटुथ सेटिङहरूमा पहुँच गर्नुहोस्"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"स्थानीय ब्लुटुथ ट्याब्लेटलाई कन्फिगर गर्नको लागि र टाढाका उपकरणहरूलाई पत्ता लगाउन र जोड्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
- <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रको ब्लुटुथ कन्फिगर गर्ने तथा टाढा रहेका यन्त्रहरू पत्ता लगाई ती यन्त्रहरूसँग जोडा बनाउने अनुमति दिन्छ।"</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"अनुप्रयोगलाई स्थानीय ब्लुटुथ फोन कन्फिगर गर्न र टाढाका उपकरणहरूसँग खोज गर्न र जोडी गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"स्थानीय ब्लुटुथ ट्याब्लेटलाई कन्फिगर गर्नको लागि र टाढाका उपकरणहरूलाई पत्ता लगाउन र जोड्नको लागि एपलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"एपलाई तपाईंको Android TV यन्त्रको ब्लुटुथ कन्फिगर गर्ने तथा टाढा रहेका यन्त्रहरू पत्ता लगाई ती यन्त्रहरूसँग जोडा बनाउने अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"एपलाई स्थानीय ब्लुटुथ फोन कन्फिगर गर्न र टाढाका उपकरणहरूसँग खोज गर्न र जोडी गर्न अनुमति दिन्छ।"</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAXसँग जोड्नुहोस् वा छुटाउनुहोस्"</string>
- <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"अनुप्रयोगलाई वाइम्याक्स सक्षम छ कि छैन र जडान भएको कुनै पनि वाइम्याक्स नेटवर्कहरूको बारेमा जानकारी निर्धारिण गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"एपलाई वाइम्याक्स सक्षम छ कि छैन र जडान भएको कुनै पनि वाइम्याक्स नेटवर्कहरूको बारेमा जानकारी निर्धारिण गर्न अनुमति दिन्छ।"</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"वाइम्याक्स अवस्था परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"अनुप्रयोगलाई वाइम्याक्स नेटवर्कहरूबाट ट्याब्लेट जडान गर्न र ट्याब्लेट विच्छेदन गर्न अनुमति दिन्छ।"</string>
- <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"अनुप्रयोगलाई तपाईंको Android TV यन्त्र WiMAX नेटवर्कहरूमा जोड्ने वा ती नेटवर्कहरूबाट विच्छेद गर्ने अनुमति दिन्छ।"</string>
- <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"वाइम्याक्स नेटवर्कहरूसँग फोन जोड्न र छुटाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"एपलाई वाइम्याक्स नेटवर्कहरूबाट ट्याब्लेट जडान गर्न र ट्याब्लेट विच्छेदन गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"एपलाई तपाईंको Android TV यन्त्र WiMAX नेटवर्कहरूमा जोड्ने वा ती नेटवर्कहरूबाट विच्छेद गर्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"वाइम्याक्स नेटवर्कहरूसँग फोन जोड्न र छुटाउन एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_bluetooth" msgid="586333280736937209">"ब्लुटुथ उपकरणहरूसँग जोडी मिलाउनुहोस्"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"ट्याब्लेटमा ब्लुटुथको कन्फिगुरेसनलाई हेर्न र बनाउन र जोडी उपकरणहरूसँग जडानहरूलाई स्वीकार गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
- <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रको ब्लुटुथको कन्फिगुरेसन हेर्ने तथा जोडा बनाइएका यन्त्रहरूसँग जोडिने वा ती यन्त्रहरूले पठाएका जोडिने अनुरोध स्वीकार्ने अनुमति दिन्छ।"</string>
- <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"अनुप्रयोगलाई फोनमा ब्लुटुथको कन्फिगरेसन हेर्न र जोडी भएका उपकरणहरूसँग जडानहरू बनाउन र स्वीकार गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"ट्याब्लेटमा ब्लुटुथको कन्फिगुरेसनलाई हेर्न र बनाउन र जोडी उपकरणहरूसँग जडानहरूलाई स्वीकार गर्न एपलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"एपलाई तपाईंको Android TV यन्त्रको ब्लुटुथको कन्फिगुरेसन हेर्ने तथा जोडा बनाइएका यन्त्रहरूसँग जोडिने वा ती यन्त्रहरूले पठाएका जोडिने अनुरोध स्वीकार्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"एपलाई फोनमा ब्लुटुथको कन्फिगरेसन हेर्न र जोडी भएका उपकरणहरूसँग जडानहरू बनाउन र स्वीकार गर्न अनुमति दिन्छ।"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"NFC भुक्तानी सेवासम्बन्धी रुचाइएको जानकारी"</string>
- <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"यसले अनुप्रयोगलाई दर्ता गरिएका सहायता तथा मार्गको गन्तव्य जस्ता रुचाइएका NFC भुक्तानी सेवासम्बन्धी जानकारी प्राप्त गर्न दिन्छ।"</string>
+ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"यसले एपलाई दर्ता गरिएका सहायता तथा मार्गको गन्तव्य जस्ता रुचाइएका NFC भुक्तानी सेवासम्बन्धी जानकारी प्राप्त गर्न दिन्छ।"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"नजिक क्षेत्र संचार नियन्त्रणहरू"</string>
- <string name="permdesc_nfc" msgid="8352737680695296741">"अनुप्रयोगलाई नयाँ क्षेत्र संचार (NFC) ट्यागहरू, कार्डहरू र पाठकहरूसँग अन्तर्क्रिया गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_nfc" msgid="8352737680695296741">"एपलाई नयाँ क्षेत्र संचार (NFC) ट्यागहरू, कार्डहरू र पाठकहरूसँग अन्तर्क्रिया गर्न अनुमति दिन्छ।"</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"स्क्रिन लक असक्षम पार्नुहोस्"</string>
- <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"कुनै सम्बन्धित पासवर्ड सुरक्षा र किलकलाई असक्षम पार्न अनुप्रयोगलाई अनुमति दिन्छ। उदाहरणको लागि, अन्तर्गमन फोन कल प्राप्त गर्दा फोनले किलकलाई असक्षम पार्छ, त्यसपछि कल सकिएको बेला किलक पुनःसक्षम पार्छ।"</string>
+ <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"कुनै सम्बन्धित पासवर्ड सुरक्षा र किलकलाई असक्षम पार्न एपलाई अनुमति दिन्छ। उदाहरणको लागि, अन्तर्गमन फोन कल प्राप्त गर्दा फोनले किलकलाई असक्षम पार्छ, त्यसपछि कल सकिएको बेला किलक पुनःसक्षम पार्छ।"</string>
<string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"स्क्रिन लकको जटिलतासम्बन्धी जानकारी प्राप्त गर्ने अनुरोध गर्नुहोस्"</string>
- <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"यसले अनुप्रयोगलाई स्क्रिन लकको जटिलताको स्तर (उच्च, मध्यम, न्यून वा कुनै पनि होइन) थाहा पाउने अनुमति दिन्छ जसले स्क्रिन लकको लम्बाइको सम्भावित दायरा र त्यसको प्रकारलाई जनाउँछ। यसै गरी, यो अनुप्रयोगले प्रयोगकर्ताहरूलाई स्क्रिन लक अद्यावधिक गर्ने सुझाव पनि दिन सक्छ तर प्रयोगकर्ताहरू उक्त सुझावको बेवास्ता गरी बाहिर निस्कन सक्छन्। स्क्रिन लक सादा पाठको ढाँचामा भण्डारण नगरिने हुँदा यो अनुप्रयोगलाई वास्तविक पासवर्ड थाहा नहुने कुराको हेक्का राख्नुहोस्।"</string>
+ <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"यसले एपलाई स्क्रिन लकको जटिलताको स्तर (उच्च, मध्यम, न्यून वा कुनै पनि होइन) थाहा पाउने अनुमति दिन्छ जसले स्क्रिन लकको लम्बाइको सम्भावित दायरा र त्यसको प्रकारलाई जनाउँछ। यसै गरी, यो अनुप्रयोगले प्रयोगकर्ताहरूलाई स्क्रिन लक अद्यावधिक गर्ने सुझाव पनि दिन सक्छ तर प्रयोगकर्ताहरू उक्त सुझावको बेवास्ता गरी बाहिर निस्कन सक्छन्। स्क्रिन लक सादा पाठको ढाँचामा भण्डारण नगरिने हुँदा यो एपलाई वास्तविक पासवर्ड थाहा नहुने कुराको हेक्का राख्नुहोस्।"</string>
<string name="permlab_useBiometric" msgid="6314741124749633786">"बायोमेट्रिक हार्डवेयर प्रयोग गर्नुहोस्"</string>
- <string name="permdesc_useBiometric" msgid="7502858732677143410">"अनुप्रयोगलाई प्रमाणीकरणका लागि बायोमेट्रिक हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
+ <string name="permdesc_useBiometric" msgid="7502858732677143410">"एपलाई प्रमाणीकरणका लागि बायोमेट्रिक हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
<string name="permlab_manageFingerprint" msgid="7432667156322821178">"फिंगरप्रिन्ट हार्डवेयर व्यवस्थापन गर्नुहोस्"</string>
- <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"अनुप्रयोगलाई प्रयोगको लागि फिंगरप्रिन्ट टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"एपलाई प्रयोगको लागि फिंगरप्रिन्ट टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"फिंगरप्रिन्ट हार्डवेयर प्रयोग गर्नुहोस्"</string>
- <string name="permdesc_useFingerprint" msgid="412463055059323742">"यो अनुप्रयोगलाई प्रमाणीकरणको लागि फिंगरप्रिन्ट हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
+ <string name="permdesc_useFingerprint" msgid="412463055059323742">"यो एपलाई प्रमाणीकरणको लागि फिंगरप्रिन्ट हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"आफ्नो सङ्गीतको सङ्ग्रह परिमार्जन गर्नुहोस्"</string>
- <string name="permdesc_audioWrite" msgid="8057399517013412431">"यसले अनुप्रयोगलाई तपाईंको सङ्गीतको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
+ <string name="permdesc_audioWrite" msgid="8057399517013412431">"यसले एपलाई तपाईंको सङ्गीतको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"आफ्नो भिडियोको सङ्ग्रह परिमार्जन गर्नुहोस्"</string>
- <string name="permdesc_videoWrite" msgid="6124731210613317051">"यसले अनुप्रयोगलाई तपाईंको भिडियोको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
+ <string name="permdesc_videoWrite" msgid="6124731210613317051">"यसले एपलाई तपाईंको भिडियोको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
<string name="permlab_imagesWrite" msgid="1774555086984985578">"आफ्नो तस्बिरको सङ्ग्रह परिमार्जन गर्नुहोस्"</string>
- <string name="permdesc_imagesWrite" msgid="5195054463269193317">"यसले अनुप्रयोगलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
+ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"यसले एपलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्"</string>
- <string name="permdesc_mediaLocation" msgid="597912899423578138">"यसले अनुप्रयोगलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string>
+ <string name="permdesc_mediaLocation" msgid="597912899423578138">"यसले एपलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string>
<string name="biometric_dialog_default_title" msgid="5284880398508155088">"यो तपाईं नै हो भन्ने पुष्टि गर्नुहोस्"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द गरियो"</string>
@@ -568,9 +568,9 @@
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिन्ट आइकन"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"फेस अनलकको हार्डवेयर व्यवस्थित गर्नुहोस्"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"अनुप्रयोगलाई प्रयोगका लागि अनुहार टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_manageFace" msgid="6204569688492710471">"एपलाई प्रयोगका लागि अनुहार टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
<string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"फेस अनलकको हार्डवेयर प्रयोग गर्नुहोस्"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"अनुप्रयोगलाई प्रमाणीकरणका लागि फेस अनलकको हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"एपलाई प्रमाणीकरणका लागि फेस अनलकको हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
<string name="face_recalibrate_notification_name" msgid="6006095897989257026">"फेस अनलक"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"आफ्नो अनुहार पुनः दर्ता गर्नुहोस्"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"अनुहार पहिचानको गुणस्तर सुधार गर्न कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्"</string>
@@ -614,33 +614,33 @@
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"एपलाई खाताको लागि सिंक सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको एप खातासँग सिंक भएको नभएको निर्धारण गर्न सक्दछ।"</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"टगल सिंक खुला र बन्द"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"अनुप्रयोगहरूलाई खाताको लागि सिंक सेटिङहरू परिमार्जन गर्न अनुमति दिन्छ। उदाहरणको लागि, यो खातासँग व्यक्ति अनुप्रयोगको सिंक सक्षम गर्न प्रयोग गर्न सकिन्छ।"</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"अनुप्रयोगहरूलाई खाताको लागि सिंक सेटिङहरू परिमार्जन गर्न अनुमति दिन्छ। उदाहरणको लागि, यो खातासँग व्यक्ति एपको सिंक सक्षम गर्न प्रयोग गर्न सकिन्छ।"</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"सिंक तथ्याङ्कहरू पढ्नुहोस्"</string>
- <string name="permdesc_readSyncStats" msgid="3867809926567379434">"अनुप्रयोगलाई खाताको लागि समीकरणको आँकडा समीकरण घटनाहरूको इतिहास र समीकरण गरिएको डेटाको मापन समेत, पढ्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_readSyncStats" msgid="3867809926567379434">"एपलाई खाताको लागि समीकरणको आँकडा समीकरण घटनाहरूको इतिहास र समीकरण गरिएको डेटाको मापन समेत, पढ्न अनुमति दिन्छ।"</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"आफ्नो आदान प्रदान गरिएको भण्डारणको सामग्रीहरूहरू पढ्नुहोस्"</string>
- <string name="permdesc_sdcardRead" msgid="6872973242228240382">"अनुप्रयोगलाई तपाईंको आदान प्रदान गरिएको भण्डारणको सामग्री पढ्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_sdcardRead" msgid="6872973242228240382">"एपलाई तपाईंको आदान प्रदान गरिएको भण्डारणको सामग्री पढ्न अनुमति दिन्छ।"</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"तपाईंको आदान प्रदान गरिएको भण्डारणको विषयवस्तुहरूलाई परिमार्जन गर्नहोस् वा मेटाउनुहोस्"</string>
- <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"अनुप्रयोगलाई तपाईंको आदान प्रदान गरिएको भण्डारणको सामग्री लेख्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"एपलाई तपाईंको आदान प्रदान गरिएको भण्डारणको सामग्री लेख्न अनुमति दिन्छ।"</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"SIP कलहरू प्राप्त/बनाउन"</string>
- <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP कलहरू बनाउन र प्राप्त गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP कलहरू बनाउन र प्राप्त गर्न एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_register_sim_subscription" msgid="1653054249287576161">"नयाँ दूरसंचार सिम जडानहरू दर्ता गर्नुहोस्"</string>
- <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"अनुप्रयोगलाई नयाँ दूरसंचार SIM जडानहरू दर्ता गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"एपलाई नयाँ दूरसंचार SIM जडानहरू दर्ता गर्न अनुमति दिन्छ।"</string>
<string name="permlab_register_call_provider" msgid="6135073566140050702">"नयाँ दूरसंचार जडानहरू दर्ता गर्नुहोस्"</string>
- <string name="permdesc_register_call_provider" msgid="4201429251459068613">"अनुप्रयोगलाई नयाँ दूरसंचार सम्पर्क दर्ता गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_register_call_provider" msgid="4201429251459068613">"एपलाई नयाँ दूरसंचार सम्पर्क दर्ता गर्न अनुमति दिन्छ।"</string>
<string name="permlab_connection_manager" msgid="3179365584691166915">"दूरसंचार जडान व्यवस्थापन गर्नुहोस्"</string>
- <string name="permdesc_connection_manager" msgid="1426093604238937733">"अनुप्रयोगलाई टेलिकम जडान व्यवस्थापन गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_connection_manager" msgid="1426093604238937733">"एपलाई टेलिकम जडान व्यवस्थापन गर्न अनुमति दिन्छ।"</string>
<string name="permlab_bind_incall_service" msgid="5990625112603493016">"आगमन कल स्क्रिन संग अन्तर्क्रिया गर्नुहोस्"</string>
- <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"कहिले र कसरी प्रयोगकर्ताले आगमन कल स्क्रीन हेर्न सक्दछ भनेर नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"कहिले र कसरी प्रयोगकर्ताले आगमन कल स्क्रीन हेर्न सक्दछ भनेर नियन्त्रण गर्न एपलाई अनुमति दिनुहोस्।"</string>
<string name="permlab_bind_connection_service" msgid="5409268245525024736">"टेलिफोनी सेवा अन्तरक्रिया"</string>
- <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"अनुप्रयोगलाई कल बनाउन/प्राप्त गर्न टेलीफोनी सेवा साथ अन्तरक्रिया गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"एपलाई कल बनाउन/प्राप्त गर्न टेलीफोनी सेवा साथ अन्तरक्रिया गर्न अनुमति दिन्छ।"</string>
<string name="permlab_control_incall_experience" msgid="6436863486094352987">"आउने-कल प्रयोगकर्ता अनुभव प्रदान गर्नुहोस्"</string>
- <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"अनुप्रयोगलाई आउने-कल प्रयोगकर्ता अनुभव प्रदान गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"एपलाई आउने-कल प्रयोगकर्ता अनुभव प्रदान गर्न अनुमति दिन्छ।"</string>
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"नेटवर्क उपयोगको इतिहास पढ्नुहोस्"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"निश्चित नेटवर्कहरू र अनुप्रयोगहरूको लागि ऐतिहासिक नेटवर्क उपयोग पढ्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"निश्चित नेटवर्कहरू र अनुप्रयोगहरूको लागि ऐतिहासिक नेटवर्क उपयोग पढ्नको लागि एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"नेटवर्क नीति प्रबन्ध गर्नुहोस्"</string>
<string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"नेटवर्क नीतिहरू व्यवस्थापन गर्न र एप-विशेष नियमहरू परिभाषित गर्न एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"नेटवर्क उपयोग लेखालाई परिमार्जन गर्नुहोस्"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"अनुप्रयोगलाई कसरी अनुप्रयोगहरूको विरूद्धमा कसरी नेटवर्क उपयोगी अकाउन्टेड छ भनेर परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूद्वारा प्रयोगको लागि होइन।"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"एपलाई कसरी अनुप्रयोगहरूको विरूद्धमा कसरी नेटवर्क उपयोगी अकाउन्टेड छ भनेर परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूद्वारा प्रयोगको लागि होइन।"</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"सूचनाहरू पहुँच गर्नुहोस्"</string>
<string name="permdesc_accessNotifications" msgid="761730149268789668">"अन्य अनुप्रयोगहरूबाट पोस्ट गरिएकासहित पुनःप्राप्त गर्न, परीक्षण गर्न र सूचनाहरू हटाउन अनुप्रयोगहरूलाई अनुमति दिन्छ।"</string>
<string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"जानकारी श्रोता सेवामा बाँध्नुहोस्"</string>
@@ -652,21 +652,21 @@
<string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"वाहक-प्रदान विन्यास एप सुरु गर्नुहोस्"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"प्रयोगकर्तालाई वाहक-प्रदान विन्यास एप सुरु गर्न अनुमति दिन्छ। साधारण एपहरूलाई कहिल्यै आवश्यक पर्ने छैन।"</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"सञ्जाल अवस्थाका पर्यवेक्षणका लागि सुन्नुहोस्"</string>
- <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"सञ्जाल अवस्थाका पर्यवेक्षण सुन्नका लागि अनुप्रयोगलाई अनुमति दिन्छ।सामान्य अनुप्रयोगलाई चाँहिदै नचाँहिन सक्छ।"</string>
+ <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"सञ्जाल अवस्थाका पर्यवेक्षण सुन्नका लागि एपलाई अनुमति दिन्छ।सामान्य एपलाई चाँहिदै नचाँहिन सक्छ।"</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"इनपुट उपकरण क्यालिब्रेसन परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"अनुप्रयोगलाई टच स्क्रीनको प्यारामिटरहरू क्यालिब्रेसन परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै आवश्यक पर्दैन।"</string>
+ <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"एपलाई टच स्क्रीनको प्यारामिटरहरू क्यालिब्रेसन परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै आवश्यक पर्दैन।"</string>
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM प्रमाणपत्रको पहुँच"</string>
<string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM प्रमाणपत्रहरू प्रावधान र प्रयोग गर्ने निवेदनको अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam स्थानान्तरण अवस्था प्राप्त गर्नुहोस्"</string>
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"यस आवेदनले वर्तमान Android Beam स्थानान्तरण बारेमा जानकारी प्राप्त गर्न अनुमति दिन्छ"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM प्रमाणपत्रहरू हटाउनुहोस्"</string>
- <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM प्रमाणपत्रहरू हटाउन अनुप्रयोगलाई अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
+ <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM प्रमाणपत्रहरू हटाउन एपलाई अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"वाहक मेसेजिङ सेवामा आबद्ध हुनुहोस्"</string>
<string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"धारकलाई वाहक मेसेजिङ सेवाको उच्च-स्तरको इन्टरफेसमा आबद्ध हुन अनुमति दिनुहोस्। सामान्य एपहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"वाहक सेवाहरु बाँध्न"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"होल्डरलाई वाहक सेवाहरु बाँध्न अनुमति दिनुहोस्। सामान्य अनुप्रयोगहरूको लागि यो कहिल्यै आवश्यक पर्दैन।"</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"बाधा नपुर्याउँनुहोस् पहुँच गर्नुहोस्"</string>
- <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्नको लागि अनुप्रयोगलाई अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्नको लागि एपलाई अनुमति दिनुहोस्।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"हेर्ने अनुमतिको प्रयोग सुरु गर्नुहोस्"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"वाहकलाई कुनै अनुप्रयोगसम्बन्धी अनुमतिको प्रयोग सुरु गर्न दिन्छ। साधारण अनुप्रयोगहरूलाई कहिल्यै आवश्यक नपर्नु पर्ने हो।"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
@@ -951,17 +951,17 @@
<string name="autofill_area" msgid="8289022370678448983">"क्षेत्र"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"इमिरेट"</string>
<string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"तपाईँका बुकमार्कहरू र इतिहास पढ्नुहोस्"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"ब्राउजरले भ्रमण गरेको सबै URL हरूको इतिहास र ब्राउजरका सबै बुकमार्कहरू पढ्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। नोट: यो अनुमतिलाई तेस्रो पक्ष ब्राउजरहरूद्वारा वा वेब ब्राउज गर्ने क्षमताद्वारा बलपूर्वक गराउन सकिँदैन।"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"ब्राउजरले भ्रमण गरेको सबै URL हरूको इतिहास र ब्राउजरका सबै बुकमार्कहरू पढ्नको लागि एपलाई अनुमति दिन्छ। नोट: यो अनुमतिलाई तेस्रो पक्ष ब्राउजरहरूद्वारा वा वेब ब्राउज गर्ने क्षमताद्वारा बलपूर्वक गराउन सकिँदैन।"</string>
<string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"वेब बुकमार्कहरू र इतिहास लेख्नुहोस्"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"अनुप्रयोगलाई तपाईंको ट्याब्लेटमा भण्डार गरिएको ब्राउजरको इतिहास वा बुकमार्कहरू परिमार्जन गर्न अनुमति दिन्छ। यसले अनुप्रयोगलाई ब्राजर डेटा मेटाउन वा परिमार्जन गर्न अनुमति दिन सक्दछ। टिप्पणी: यो अनुमति वेब ब्राउज गर्ने क्षमताहरूको साथ तेस्रो-पार्टी ब्राउजर वा अन्य अनुप्रयोगहरूद्वारा लागू गरिएको होइन।"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रमा भण्डार गरिएका ब्राउजरको इतिहास र पुस्तक चिन्हहरू परिमार्जन गर्ने अनुमति दिन्छ। यसले अनुप्रयोगलाई ब्राउजरको डेटा मेटाउने वा परिमार्जन गर्ने अनुमति दिन सक्छ। ध्यान दिनुहोस्: तेस्रो पक्षीय ब्राउजर वा वेब ब्राउज गर्ने सुविधा प्रदान गर्ने अन्य अनुप्रयोगहरूले यो अनुमति लागू गर्न सक्दैनन्।"</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"तपाईँको फोनमा भण्डारण भएको ब्राउजरको इतिहास वा बुकमार्कहरू परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। यसले सायद ब्राउजर डेटालाई मेट्न वा परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। नोट: वेब ब्राउज गर्ने क्षमतासहितका अन्य एपहरू वा तेस्रो- पक्ष ब्राउजरद्वारा सायद यस अनुमतिलाई लागु गर्न सकिंदैन।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"एपलाई तपाईंको ट्याब्लेटमा भण्डार गरिएको ब्राउजरको इतिहास वा बुकमार्कहरू परिमार्जन गर्न अनुमति दिन्छ। यसले एपलाई ब्राजर डेटा मेटाउन वा परिमार्जन गर्न अनुमति दिन सक्दछ। टिप्पणी: यो अनुमति वेब ब्राउज गर्ने क्षमताहरूको साथ तेस्रो-पार्टी ब्राउजर वा अन्य अनुप्रयोगहरूद्वारा लागू गरिएको होइन।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"एपलाई तपाईंको Android TV यन्त्रमा भण्डार गरिएका ब्राउजरको इतिहास र पुस्तक चिन्हहरू परिमार्जन गर्ने अनुमति दिन्छ। यसले एपलाई ब्राउजरको डेटा मेटाउने वा परिमार्जन गर्ने अनुमति दिन सक्छ। ध्यान दिनुहोस्: तेस्रो पक्षीय ब्राउजर वा वेब ब्राउज गर्ने सुविधा प्रदान गर्ने अन्य एपहरूले यो अनुमति लागू गर्न सक्दैनन्।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"तपाईँको फोनमा भण्डारण भएको ब्राउजरको इतिहास वा बुकमार्कहरू परिवर्तन गर्नको लागि एपलाई अनुमति दिन्छ। यसले सायद ब्राउजर डेटालाई मेट्न वा परिवर्तन गर्नको लागि एपलाई अनुमति दिन्छ। नोट: वेब ब्राउज गर्ने क्षमतासहितका अन्य एपहरू वा तेस्रो- पक्ष ब्राउजरद्वारा सायद यस अनुमतिलाई लागु गर्न सकिंदैन।"</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"एउटा आलर्म सेट गर्नुहोस्"</string>
- <string name="permdesc_setAlarm" msgid="2185033720060109640">"स्थापना गरिएको सङ्केत घडी अनुप्रयोगमा सङ्केत समय मिलाउन अनुप्रयोगलाई अनुमति दिन्छ। केही सङ्केत घडी अनुप्रयोगहरूले यो सुविधा कार्यान्वयन नगर्न सक्छन्।"</string>
+ <string name="permdesc_setAlarm" msgid="2185033720060109640">"स्थापना गरिएको सङ्केत घडी अनुप्रयोगमा सङ्केत समय मिलाउन एपलाई अनुमति दिन्छ। केही सङ्केत घडी एपहरूले यो सुविधा कार्यान्वयन नगर्न सक्छन्।"</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"भ्वाइसमेल थप गर्नुहोस्"</string>
- <string name="permdesc_addVoicemail" msgid="5470312139820074324">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश थप्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_addVoicemail" msgid="5470312139820074324">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश थप्नको लागि एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"भूस्थान अनुमतिहरू ब्राउजर परिवर्तन गर्नुहोस्"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"ब्राउजरको भू-स्थान अनुमतिहरू परिमार्जन गर्न अनुप्रयोगलाई अनुमति दिन्छ। खराब अनुप्रयोगहरूले स्थान सूचना मनपरी वेब साइटहरूमा पठाउने अनुमतिको लागि यसलाई प्रयोग गर्न सक्छन्।"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"ब्राउजरको भू-स्थान अनुमतिहरू परिमार्जन गर्न एपलाई अनुमति दिन्छ। खराब एपहरूले स्थान सूचना मनपरी वेब साइटहरूमा पठाउने अनुमतिको लागि यसलाई प्रयोग गर्न सक्छन्।"</string>
<string name="save_password_message" msgid="2146409467245462965">"के तपाईं ब्राउजरले यो पासवर्ड सम्झेको चाहनुहुन्छ?"</string>
<string name="save_password_notnow" msgid="2878327088951240061">"अहिले होइन"</string>
<string name="save_password_remember" msgid="6490888932657708341">"सम्झनुहोस्"</string>
@@ -1111,7 +1111,7 @@
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"सायद केही प्रणाली कार्यक्रमहरूले काम गर्दैनन्"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"प्रणालीको लागि पर्याप्त भण्डारण छैन। तपाईँसँग २५० मेगा बाइट ठाउँ खाली भएको निश्चित गर्नुहोस् र फेरि सुरु गर्नुहोस्।"</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> चलिरहेको छ"</string>
- <string name="app_running_notification_text" msgid="5120815883400228566">"थप जानकारीका लागि वा अनुप्रयोगलाई बन्द गर्न ट्याप गर्नुहोस्।"</string>
+ <string name="app_running_notification_text" msgid="5120815883400228566">"थप जानकारीका लागि वा एपलाई बन्द गर्न ट्याप गर्नुहोस्।"</string>
<string name="ok" msgid="2646370155170753815">"ठिक छ"</string>
<string name="cancel" msgid="6908697720451760115">"रद्द गर्नुहोस्"</string>
<string name="yes" msgid="9069828999585032361">"ठिक छ"</string>
@@ -1159,12 +1159,12 @@
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"प्रणाली सेटिङहरूमा पूर्वनिर्धारितलाई हटाउनुहोस् > एपहरू > डाउनलोड।"</string>
<string name="chooseActivity" msgid="8563390197659779956">"एउटा कार्यको चयन गर्नुहोस्"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USB उपकरणको लागि एउटा एप छान्नुहोस्"</string>
- <string name="noApplications" msgid="1186909265235544019">"कुनै पनि अनुप्रयोगहरूले यो कार्य गर्न सक्दैनन्।"</string>
+ <string name="noApplications" msgid="1186909265235544019">"कुनै पनि एपहरूले यो कार्य गर्न सक्दैनन्।"</string>
<string name="aerr_application" msgid="4090916809370389109">"<xliff:g id="APPLICATION">%1$s</xliff:g> रोकिएको छ"</string>
<string name="aerr_process" msgid="4268018696970966407">"<xliff:g id="PROCESS">%1$s</xliff:g> रोकिएको छ"</string>
<string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> रोकिरहन्छ"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> रोकिरहन्छ"</string>
- <string name="aerr_restart" msgid="2789618625210505419">"अनुप्रयोगलाई फेरि खोल्नुहोस्"</string>
+ <string name="aerr_restart" msgid="2789618625210505419">"एपलाई फेरि खोल्नुहोस्"</string>
<string name="aerr_report" msgid="3095644466849299308">"प्रतिक्रिया पठाउनुहोस्"</string>
<string name="aerr_close" msgid="3398336821267021852">"बन्द गर्नुहोस्"</string>
<string name="aerr_mute" msgid="2304972923480211376">"यन्त्र पुनः सुरु नभएसम्म म्यूट गर्नुहोस्"</string>
@@ -1187,7 +1187,7 @@
<string name="screen_compat_mode_hint" msgid="4032272159093750908">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् > एपहरू > डाउनलोड गरेको।"</string>
<string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले हालको प्रदर्शनको आकार सम्बन्धी सेटिङलाई समर्थन गर्दैन र अप्रत्याशित तरिकाले व्यवहार गर्न सक्छ।"</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"सधैँ देखाउनुहोस्"</string>
- <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई Android OS को कुनै नमिल्दो संस्करणका लागि निर्माण गरिएको थियो र यसले अप्रत्याशित ढंगले कार्य गर्नसक्छ। उक्त अनुप्रयोगको कुनै अद्यावधिक संस्करण उपलब्ध हुनसक्छ।"</string>
+ <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई Android OS को कुनै नमिल्दो संस्करणका लागि निर्माण गरिएको थियो र यसले अप्रत्याशित ढंगले कार्य गर्नसक्छ। उक्त एपको कुनै अद्यावधिक संस्करण उपलब्ध हुनसक्छ।"</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"जुनसुकै बेला देखाउनुहोस्"</string>
<string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"अद्यावधिकका लागि जाँच गर्नुहोस्"</string>
<string name="smv_application" msgid="3775183542777792638">"एप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ले यसको स्वयं-लागु गरिएको स्ट्रिटमोड नीति उलङ्घन गरेको छ।"</string>
@@ -1217,7 +1217,7 @@
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"<xliff:g id="PROC">%1$s</xliff:g> हिप डम्प तयार छ"</string>
<string name="dump_heap_notification_detail" msgid="8431586843001054050">"हिप डम्प सङ्कलन गरियो, ट्याप गरेर सेयर गर्नुहोस्।"</string>
<string name="dump_heap_title" msgid="4367128917229233901">"हिप डम्प साझेदारी गर्नुहुन्छ?"</string>
- <string name="dump_heap_text" msgid="1692649033835719336">"<xliff:g id="PROC">%1$s</xliff:g>प्रक्रियाले यसको मेमोरीको सीमा <xliff:g id="SIZE">%2$s</xliff:g> नाघेको छ। तपाईंका लागि विकासकर्तासँग साझेदारी गर्न एउटा हिप डम्प उपलब्ध छ। सावधान हुनुहोला: यो हिप डम्पमा अनुप्रयोगको पहुँच भएको तपाईंको जुनसुकै व्यक्तिगत जानकारी हुन सक्छ।"</string>
+ <string name="dump_heap_text" msgid="1692649033835719336">"<xliff:g id="PROC">%1$s</xliff:g>प्रक्रियाले यसको मेमोरीको सीमा <xliff:g id="SIZE">%2$s</xliff:g> नाघेको छ। तपाईंका लागि विकासकर्तासँग साझेदारी गर्न एउटा हिप डम्प उपलब्ध छ। सावधान हुनुहोला: यो हिप डम्पमा एपको पहुँच भएको तपाईंको जुनसुकै व्यक्तिगत जानकारी हुन सक्छ।"</string>
<string name="dump_heap_system_text" msgid="6805155514925350849">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियाले यसको मेमोरीको सीमा <xliff:g id="SIZE">%2$s</xliff:g> नाँघेको छ। आदान प्रदान गर्नका लागि तपाईंलाई एउटा हिप डम्प उपलब्ध छ। सावधान हुनुहोस्: यस हिप डम्पमा उक्त प्रक्रियाको पहुँच भएको जुनसुकै संवेदनशील व्यक्तिगत जानकारी समावेश हुन सक्छ जसमा तपाईंले टाइप गर्नुभएका कुराहरू पर्न सक्छन्।"</string>
<string name="dump_heap_ready_text" msgid="5849618132123045516">"तपाईंसँग आदान प्रदान गर्नका लागि <xliff:g id="PROC">%1$s</xliff:g> को प्रक्रियासम्बन्धी हिप डम्प उपलब्ध छ। सावधान हुनुहोस्: यस हिप डम्पमा उक्त प्रक्रियाको पहुँच भएको जुनसुकै संवेदनशील व्यक्तिगत जानकारी समावेश हुन सक्छ जसमा तपाईंले टाइप गर्नुभएका कुराहरू पर्न सक्छन्।"</string>
<string name="sendText" msgid="493003724401350724">"पाठको लागि एउटा प्रकार्य छान्नुहोस्"</string>
@@ -1268,7 +1268,7 @@
<string name="decline" msgid="6490507610282145874">"अस्वीकार गर्नुहोस्"</string>
<string name="select_character" msgid="3352797107930786979">"अक्षरहरू प्रवेश गराउनुहोस्"</string>
<string name="sms_control_title" msgid="4748684259903148341">"SMS सन्देशहरू पठाइँदै"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ले धरै संख्यामा SMS सन्देशहरू पठाउँदैछ। के तपाईं यस अनुप्रयोगलाई सन्देशहरू पठाउन सुचारु गर्न अनुमति दिन चाहनु हुन्छ?"</string>
+ <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ले धरै संख्यामा SMS सन्देशहरू पठाउँदैछ। के तपाईं यस एपलाई सन्देशहरू पठाउन सुचारु गर्न अनुमति दिन चाहनु हुन्छ?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"अनुमति दिनुहोस्"</string>
<string name="sms_control_no" msgid="4845717880040355570">"अस्वीकार गर्नुहोस्"</string>
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> के तपाईं सन्देश पठाउन चाहुनु हुन्छ <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
@@ -1340,8 +1340,8 @@
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अन्य अनुप्रयोगमा देखाउनुहोस्"</string>
- <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> अन्य अनुप्रयोगहरूमा देखिँदैछ"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> अन्य अनुप्रयोगहरूमा देखिँदैछ"</string>
+ <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> अन्य एपहरूमा देखिँदैछ"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> अन्य एपहरूमा देखिँदैछ"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले यो विशेषता प्रयोग नगरेको चाहनुहुन्न भने सेटिङहरू खोली यसलाई निष्क्रिय पार्न ट्याप गर्नुहोस्।"</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"निष्क्रिय पार्नुहोस्"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"जाँच गर्दै <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1389,15 +1389,15 @@
<string name="ext_media_status_missing" msgid="6520746443048867314">"सम्मिलित छैन"</string>
<string name="activity_list_empty" msgid="4219430010716034252">"कुनै मिल्ने गतिविधि पाइएन।"</string>
<string name="permlab_route_media_output" msgid="8048124531439513118">"मिडिया निकास दिशानिर्देश गराउनुहोस्"</string>
- <string name="permdesc_route_media_output" msgid="1759683269387729675">"मिडिया परिणामलाई अन्य बाहिरी उपकरणहरूसँग लैजानको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_route_media_output" msgid="1759683269387729675">"मिडिया परिणामलाई अन्य बाहिरी उपकरणहरूसँग लैजानको लागि एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_readInstallSessions" msgid="7279049337895583621">"स्थापना सत्रहरू पढ्नु दिनुहोस्"</string>
- <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"स्थापित सत्र पढ्न अनुप्रयोगलाई अनुमति दिनुहोस्। यसले सक्रिय प्याकेज प्रतिष्ठानहरू बारेमा विवरण हेर्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"स्थापित सत्र पढ्न एपलाई अनुमति दिनुहोस्। यसले सक्रिय प्याकेज प्रतिष्ठानहरू बारेमा विवरण हेर्ने अनुमति दिन्छ।"</string>
<string name="permlab_requestInstallPackages" msgid="7600020863445351154">"स्थापना प्याकेजहरू अनुरोध गर्नुहोस्"</string>
- <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"प्याकेजहरूको स्थापना अनुरोध गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"प्याकेजहरूको स्थापना अनुरोध गर्न एपलाई अनुमति दिन्छ।"</string>
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"प्याकेजहरू मेटाउने अनुरोध गर्नुहोस्"</string>
- <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"अनुप्रयोगलाई प्याकेजहरू मेटाउने अनुरोध गर्न अनुमति दिन्छ।"</string>
+ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"एपलाई प्याकेजहरू मेटाउने अनुरोध गर्न अनुमति दिन्छ।"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्न सोध्नुहोस्"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"कुनै अनुप्रयोगलाई त्यसका ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्नाका लागि अनुमति माग्न दिन्छ।"</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"कुनै एपलाई त्यसका ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्नाका लागि अनुमति माग्न दिन्छ।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"जुम नियन्त्रणको लागि दुई चोटि ट्याप गर्नुहोस्"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"विजेट थप गर्न सकिँदैन।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"जानुहोस्"</string>
@@ -1409,7 +1409,7 @@
<string name="ime_action_default" msgid="8265027027659800121">"चलाउनुहोस्"</string>
<string name="dial_number_using" msgid="6060769078933953531">\n"नम्बर डायल गर्नुहोस् <xliff:g id="NUMBER">%s</xliff:g> प्रयोग गरेर"</string>
<string name="create_contact_using" msgid="6200708808003692594">"सम्पर्क सिर्जना गर्नुहोस्\nयो <xliff:g id="NUMBER">%s</xliff:g> प्रयोग गरेर"</string>
- <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"निम्न एउटा वा धेरै अनुप्रयोगहरूले तपाईँको खातामा पहुँचको लागि अनुमति अहिले र भविष्यमा अनुरोध गर्छन्।"</string>
+ <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"निम्न एउटा वा धेरै एपहरूले तपाईँको खातामा पहुँचको लागि अनुमति अहिले र भविष्यमा अनुरोध गर्छन्।"</string>
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"के तपाईं यस अनुरोधलाई अनुमति दिन चाहनुहुन्छ?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"अनुरोध पहुँच गर्नुहोस्"</string>
<string name="allow" msgid="6195617008611933762">"अनुमति दिनुहोस्"</string>
@@ -1528,7 +1528,7 @@
<string name="data_usage_restricted_title" msgid="126711424380051268">"पृष्ठभूमिका डेटा प्रतिबन्धित गरिएको छ"</string>
<string name="data_usage_restricted_body" msgid="5338694433686077733">"सीमिततालाई हटाउन ट्याप गर्नुहोस्।"</string>
<string name="data_usage_rapid_title" msgid="2950192123248740375">"मोबाइल डेटाको उच्च प्रयोग"</string>
- <string name="data_usage_rapid_body" msgid="3886676853263693432">"तपाईंका अनुप्रयोगहरूले सामान्यभन्दा बढी डेटा प्रयोग गरेका छन्"</string>
+ <string name="data_usage_rapid_body" msgid="3886676853263693432">"तपाईंका एपहरूले सामान्यभन्दा बढी डेटा प्रयोग गरेका छन्"</string>
<string name="data_usage_rapid_app_body" msgid="5425779218506513861">"<xliff:g id="APP">%s</xliff:g> ले सामान्यभन्दा बढी डेटा प्रयोग गरेको छ"</string>
<string name="ssl_certificate" msgid="5690020361307261997">"सुरक्षा प्रमाणपत्र"</string>
<string name="ssl_certificate_is_valid" msgid="7293675884598527081">"प्रमाणपत्र मान्य छ।"</string>
@@ -1643,7 +1643,7 @@
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"तपाईंले <xliff:g id="SERVICE">%1$s</xliff:g> सक्रिय गर्नुभयो भने तपाईंको यन्त्रले डेटा इन्क्रिप्ट गर्ने सुविधाको स्तरोन्नति गर्न तपाईंको स्क्रिन लक सुविधाको प्रयोग गर्ने छैन।"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"तपाईंलाई पहुँच राख्न आवश्यक पर्ने कुरामा सहयोग गर्ने अनुप्रयोगहरूमाथि पूर्ण नियन्त्रण गर्नु उपयुक्त हुन्छ तर अधिकांश अनुप्रयोगहरूका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रिन हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यसले स्क्रिनमा देखिने सबै सामग्री पढ्न सक्छ र अन्य अनुप्रयोगहरूमा उक्त सामग्री देखाउन सक्छ।"</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यसले स्क्रिनमा देखिने सबै सामग्री पढ्न सक्छ र अन्य एपहरूमा उक्त सामग्री देखाउन सक्छ।"</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"कारबाहीहरू हेर्नुहोस् र तिनमा कार्य गर्नुहोस्"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"यसले कुनै एप वा हार्डवेयर सेन्सरसँग तपाईंले गर्ने अन्तर्क्रियाको ट्र्याक गर्न सक्छ र तपाईंका तर्फबाट एपहरूसँग अन्तर्क्रिया गर्न सक्छ।"</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमति दिनुहोस्"</string>
@@ -1802,7 +1802,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string>
<string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ब्याट्रीको आयु बढाउन ब्याट्री सेभरले:\n\n•अँध्यारो थिम सक्रिय गर्छ\n•पृष्ठभूमिका गतिविधि, केही दृश्यात्मक प्रभाव तथा “Hey Google” जस्ता अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ\n\n"<annotation id="url">"थप जान्नुहोस्"</annotation></string>
<string name="battery_saver_description" msgid="8587408568232177204">"ब्याट्रीको आयु बढाउन ब्याट्री सेभरले:\n\n•अँध्यारो थिम सक्रिय गर्छ\n•पृष्ठभूमिका गतिविधि, केही दृश्यात्मक प्रभाव तथा “Hey Google” जस्ता अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ"</string>
- <string name="data_saver_description" msgid="4995164271550590517">"डेटाको प्रयोगलाई कम गर्न डेटा सर्भरले केही अनुप्रयोगलाई पृष्ठभूमिमा डेटा पठाउन वा प्राप्त गर्न दिँदैन। तपाईंले हाल प्रयोग गरिरहनुभएको अनु्प्रयोगले डेटा चलाउन सक्छ, तर पहिला भन्दा कम अन्तरालमा मात्र। उदाहरणका लागि, तपाईले छविहरूमा ट्याप नगरेसम्म ती छविहरू देखिँदैनन्।"</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"डेटाको प्रयोगलाई कम गर्न डेटा सर्भरले केही एपलाई पृष्ठभूमिमा डेटा पठाउन वा प्राप्त गर्न दिँदैन। तपाईंले हाल प्रयोग गरिरहनुभएको अनु्प्रयोगले डेटा चलाउन सक्छ, तर पहिला भन्दा कम अन्तरालमा मात्र। उदाहरणका लागि, तपाईले छविहरूमा ट्याप नगरेसम्म ती छविहरू देखिँदैनन्।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेभर सक्रिय गर्ने हो?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सक्रिय गर्नुहोस्"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -1982,7 +1982,7 @@
<string name="mmcc_illegal_me_msim_template" msgid="4802735138861422802">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> लाई अनुमति छैन"</string>
<string name="popup_window_default_title" msgid="6907717596694826919">"पपअप विन्डो"</string>
<string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"या त अनुप्रयोगको संस्करण स्तरह्रास गरियो वा यो यस सर्टकटसँग मिल्दो छैन"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"या त एपको संस्करण स्तरह्रास गरियो वा यो यस सर्टकटसँग मिल्दो छैन"</string>
<string name="shortcut_restore_not_supported" msgid="4763198938588468400">"अनुप्रयोगले ब्याकअप तथा पुनर्स्थापनालाई समर्थन नगर्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
<string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"अनुप्रयोगमा प्रयोग गरिने हस्ताक्षर नमिल्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
@@ -2004,12 +2004,12 @@
<string name="notification_app_name_settings" msgid="9088548800899952531">"सेटिङहरू"</string>
<string name="notification_appops_camera_active" msgid="8177643089272352083">"क्यामेरा"</string>
<string name="notification_appops_microphone_active" msgid="581333393214739332">"माइक्रोफोन"</string>
- <string name="notification_appops_overlay_active" msgid="5571732753262836481">"तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमा प्रदर्शन गरिँदै छ"</string>
+ <string name="notification_appops_overlay_active" msgid="5571732753262836481">"तपाईंको स्क्रिनका अन्य एपहरूमा प्रदर्शन गरिँदै छ"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनचर्या मोडको जानकारीमूलक सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"प्रायः चार्ज गर्ने समय हुनुभन्दा पहिले नै ब्याट्री सकिन सक्छ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ब्याट्रीको आयु बढाउन ब्याट्री सेभर सक्रिय गरियो"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ब्याट्री सेभर"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ब्याट्री सेभर निष्क्रिय पारियो"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ब्याट्री सेभर अफ गरियो"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"फोनमा पर्याप्त चार्ज छ। सुविधाहरूलाई अब उप्रान्त प्रतिबन्ध लगाइँदैन।"</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"ट्याब्लेटमा पर्याप्त चार्ज छ। सुविधाहरूलाई अब उप्रान्त प्रतिबन्ध लगाइँदैन।"</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"यन्त्रमा पर्याप्त चार्ज छ। सुविधाहरूलाई अब उप्रान्त प्रतिबन्ध लगाइँदैन।"</string>
@@ -2039,7 +2039,7 @@
</plurals>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"कुनै पनि व्यक्तिसँग सेयर गर्ने सिफारिस गरिएको छैन"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"अनुप्रयोगहरूको सूची"</string>
- <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"यो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले यो USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"यो एपलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले यो USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"गृहपृष्ठ"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"पछाडि फर्कनुहोस्"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"हालसालैका एपहरू"</string>
@@ -2048,12 +2048,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पावर संवाद"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"सहज पहुँचका लागि स्क्रिनमा राखिने सर्टकट"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"सहज पहुँचका लागि स्क्रिनमा राखिने सर्टकट छान्ने मेनु"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"पहुँचको सर्टकट"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> को क्याप्सन बार।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2187,4 +2184,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID अनलक गरियो।"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI अनलक गरियो।"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"नेटवर्कको सबसेटको सेवा प्रदायकसम्बन्धी लक खोलियो।"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 708b4f3..98fece3 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -35,4 +35,6 @@
<color name="resolver_empty_state_text">#FFFFFF</color>
<color name="resolver_empty_state_icon">#FFFFFF</color>
+
+ <color name="personal_apps_suspension_notification_color">#8AB4F8</color>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f320e5d..d379c8f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Voedingsdialoogvenster"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Scherm vergrendelen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Snelkoppeling voor toegankelijkheid op scherm"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Kiezer voor snelkoppeling voor toegankelijkheid op scherm"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Snelkoppeling voor toegankelijkheid"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID is ontgrendeld."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI is ontgrendeld."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Subset van netwerk serviceprovider is ontgrendeld."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 28f552e..bc859c1 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -142,7 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"ୱାଇ-ଫାଇ"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ୱାଇଫାଇ କଲିଂ"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <string name="wifi_calling_off_summary" msgid="5626710010766902560">"ଅଫ୍"</string>
+ <string name="wifi_calling_off_summary" msgid="5626710010766902560">"ବନ୍ଦ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ କଲ୍ କରନ୍ତୁ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ମୋବାଇଲ ନେଟ୍ୱର୍କ ମାଧ୍ୟମରେ କଲ୍ କରନ୍ତୁ"</string>
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"କେବଳ ୱାଇ-ଫାଇ"</string>
@@ -1119,7 +1119,7 @@
<string name="dialog_alert_title" msgid="651856561974090712">"ଧ୍ୟାନଦିଅନ୍ତୁ"</string>
<string name="loading" msgid="3138021523725055037">"ଲୋଡ୍ କରାଯାଉଛି…"</string>
<string name="capital_on" msgid="2770685323900821829">"ଚାଲୁ"</string>
- <string name="capital_off" msgid="7443704171014626777">"ଅଫ୍"</string>
+ <string name="capital_off" msgid="7443704171014626777">"ବନ୍ଦ"</string>
<string name="checked" msgid="9179896827054513119">"ଯାଞ୍ଚ ହୋଇଛି"</string>
<string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string>
<string name="whichApplication" msgid="5432266899591255759">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
@@ -1231,7 +1231,7 @@
<string name="volume_icon_description_notification" msgid="579091344110747279">"ବିଜ୍ଞପ୍ତି ଭଲ୍ୟୁମ୍"</string>
<string name="ringtone_default" msgid="9118299121288174597">"ଡିଫଲ୍ଟ ରିଙ୍ଗଟୋନ୍"</string>
<string name="ringtone_default_with_actual" msgid="2709686194556159773">"ଡିଫଲ୍ଟ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="397111123930141876">"କିଛିନୁହେଁ"</string>
+ <string name="ringtone_silent" msgid="397111123930141876">"କିଛି ନାହିଁ"</string>
<string name="ringtone_picker_title" msgid="667342618626068253">"ରିଙ୍ଗଟୋନ୍"</string>
<string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"ଆଲାରାମ୍ ଶବ୍ଦ"</string>
<string name="ringtone_picker_title_notification" msgid="6387191794719608122">"ବିଜ୍ଞପ୍ତି ଶବ୍ଦ"</string>
@@ -1796,7 +1796,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string>
<string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ବ୍ୟାଟେରୀ ଲାଇଫ୍ ବଢ଼ାଇବାକୁ ବ୍ୟାଟେରୀ ସେଭର୍:\n\n•ଗାଢ଼ା ଥିମ୍ ଚାଲୁ କରେ\n•ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବ ଏବଂ “Hey Google” ପରି ଅନ୍ୟ ଫିଚରଗୁଡ଼ିକୁ ବନ୍ଦ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ\n\n"<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
<string name="battery_saver_description" msgid="8587408568232177204">"ବ୍ୟାଟେରୀ ଲାଇଫ୍ ବଢ଼ାଇବାକୁ ବ୍ୟାଟେରୀ ସେଭର୍:\n\n•ଗାଢ଼ା ଥିମ୍ ଚାଲୁ କରେ\n•ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବ ଏବଂ “Hey Google” ପରି ଅନ୍ୟ ଫିଚରଗୁଡ଼ିକୁ ବନ୍ଦ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ"</string>
- <string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍, ଡାଟା ଆକ୍ସେସ୍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଟାପ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଇମେଜ୍ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍, ଡାଟା ଆକ୍ସେସ୍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଇମେଜଗୁଡ଼ିକୁ ଟାପ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ସେଗୁଡ଼ିକ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍ ଚାଲୁ କରିବେ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ଚାଲୁ କରନ୍ତୁ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -1922,7 +1922,7 @@
<string name="app_category_maps" msgid="6395725487922533156">"ମାନଚିତ୍ର ଓ ନେଭିଗେଶନ୍"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ଉତ୍ପାଦକତା"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ଡିଭାଇସ୍ ଷ୍ଟୋରେଜ୍"</string>
- <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ଡିବଗିଙ୍ଗ"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ଡିବଗିଂ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ଘଣ୍ଟା"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"ମିନିଟ୍"</string>
<string name="time_picker_header_text" msgid="9073802285051516688">"ସମୟ ସେଟ୍ କରନ୍ତୁ"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ପାୱାର ଡାୟଲଗ୍ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ଅନ୍-ସ୍କ୍ରିନ୍ ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ଅନ୍-ସ୍କ୍ରିନ୍ ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍ ବାଛିବା ସୁବିଧା"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID ଅନଲକ୍ କରିବା ସଫଳ ହୋଇଛି।"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI ଅନଲକ୍ କରିବା ସଫଳ ହୋଇଛି।"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ନେଟୱାର୍କ ସବସେଟର ସେବା ପ୍ରଦାନକାରୀକୁ ଅନଲକ୍ କରିବା ସଫଳ ହୋଇଛି।"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index e0c6056..5df7e29 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ਪਾਵਰ ਵਿੰਡੋ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਣ ਵਾਲਾ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਣ ਵਾਲੇ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਦਾ ਚੋਣਕਾਰ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID ਅਣਲਾਕ ਸਫਲ।"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI ਅਣਲਾਕ ਸਫਲ।"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ਨੈੱਟਵਰਕ ਸਬਸੈੱਟ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਅਣਲਾਕ ਸਫਲ।"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c12c9ae..3e790c7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -243,8 +243,8 @@
<string name="global_action_power_off" msgid="4404936470711393203">"Wyłącz"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Przycisk zasilania"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Uruchom ponownie"</string>
- <string name="global_action_emergency" msgid="1387617624177105088">"Alarmowy"</string>
- <string name="global_action_bug_report" msgid="5127867163044170003">"Zgłoszenie błędu"</string>
+ <string name="global_action_emergency" msgid="1387617624177105088">"Nagły przypadek"</string>
+ <string name="global_action_bug_report" msgid="5127867163044170003">"Zgłoś błąd"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Zakończ sesję"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Zrzut ekranu"</string>
<string name="bugreport_title" msgid="8549990811777373050">"Zgłoś błąd"</string>
@@ -1840,8 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n•włącza tryb ciemny,\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n•włącza tryb ciemny,\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n•włącza tryb ciemny\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n•włącza tryb ciemny\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string>
@@ -1916,7 +1916,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Żądanie SS zmienione na rozmowę wideo"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Żądanie SS zmienione na żądanie USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Zmieniono na nowe żądanie SS"</string>
- <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil służbowy"</string>
+ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil do pracy"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alert"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozwiń"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Zwiń"</string>
@@ -1952,7 +1952,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie jest teraz dostępna. Zarządza tym aplikacja <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Więcej informacji"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Wznów działanie aplikacji"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Włączyć profil służbowy?"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Włączyć profil do pracy?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacje do pracy, powiadomienia, dane i inne funkcje profilu do pracy zostaną włączone"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Okno opcji zasilania"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranowy skrót ułatwień dostępu"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Wybierz ekranowy skrót ułatwień dostępu"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Skrót ułatwień dostępu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Odblokowano ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Odblokowano IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Odblokowano usługodawcę w podzbiorze sieci."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index dbd69a1..9908e38 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -240,7 +240,7 @@
<string name="global_action_power_options" msgid="1185286119330160073">"Desligar"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Reiniciar"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Emergência"</string>
- <string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de bugs"</string>
+ <string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar sessão"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de tela"</string>
<string name="bugreport_title" msgid="8549990811777373050">"Relatório de bug"</string>
@@ -1797,7 +1797,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
<string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar Economia de dados?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de liga/desliga"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atalho de acessibilidade na tela"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Seletor de atalho de acessibilidade na tela"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atalho de acessibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Desbloqueio do ICCID concluído."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Desbloqueio de IMPI concluído."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Desbloqueio do provedor de serviços de subconjunto de rede concluído."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6bd1dfa..3db4133 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1159,7 +1159,7 @@
<string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> continua a falhar"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> continua a falhar"</string>
<string name="aerr_restart" msgid="2789618625210505419">"Abrir app novamente"</string>
- <string name="aerr_report" msgid="3095644466849299308">"Enviar comentários"</string>
+ <string name="aerr_report" msgid="3095644466849299308">"Enviar feedback"</string>
<string name="aerr_close" msgid="3398336821267021852">"Fechar"</string>
<string name="aerr_mute" msgid="2304972923480211376">"Desativar som até o dispositivo reiniciar"</string>
<string name="aerr_wait" msgid="3198677780474548217">"Aguardar"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de energia"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecrã de bloqueio"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de ecrã"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atalho de acessibilidade no ecrã"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selecionador de atalhos de acessibilidade no ecrã"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atalho de acessibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"O desbloqueio do ICCID foi bem-sucedido."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"O desbloqueio do IMPI foi bem-sucedido."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"O desbloqueio do fornecedor de serviços do subconjunto da rede foi bem-sucedido."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index dbd69a1..9908e38 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -240,7 +240,7 @@
<string name="global_action_power_options" msgid="1185286119330160073">"Desligar"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Reiniciar"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Emergência"</string>
- <string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de bugs"</string>
+ <string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar sessão"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de tela"</string>
<string name="bugreport_title" msgid="8549990811777373050">"Relatório de bug"</string>
@@ -1797,7 +1797,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
<string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar Economia de dados?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de liga/desliga"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atalho de acessibilidade na tela"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Seletor de atalho de acessibilidade na tela"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atalho de acessibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Desbloqueio do ICCID concluído."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Desbloqueio de IMPI concluído."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Desbloqueio do provedor de serviços de subconjunto de rede concluído."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 02e3fda..5143fc7 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2076,12 +2076,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Comandă rapidă de accesibilitate de pe ecran"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector de comenzi rapide de accesibilitate de pe ecran"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Comandă rapidă de accesibilitate"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2215,4 +2212,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"S-a realizat deblocarea ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"S-a realizat deblocarea IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"S-a realizat deblocarea privind furnizorul de servicii și subsetul de rețea."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index b804754..fdcb3f2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Диалоговое окно питания"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Действие для быстрого включения"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Выбор действия для быстрого включения"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Быстрое включение"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Разблокировка ICCID завершена."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Разблокировка IMPI завершена."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Разблокировка подмножества сети оператора завершена."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 103bc39..4f5de45 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2044,12 +2044,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"බල සංවාදය"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"තිරය මත ප්රවේශ්යතා කෙටිමග"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"තිරය මත ප්රවේශ්යතා කෙටිමං තෝරනය"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ප්රවේශ්යතා කෙටිමඟ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2183,4 +2180,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID අගුලු හැරීම සාර්ථකයි."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI අගුලු හැරීම සාර්ථකයි."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ජාල උප කට්ටල සේවා සැපයුම්කරු අගුලු හැරීම අසාර්ථකයි."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 485ee11..492a83e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1705,7 +1705,7 @@
<string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funkcie prepnete pridržaním tlačidla dostupnosti."</string>
<string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Funkcie prepnete potiahnutím dvoma prstami nahor a pridržaním."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Funkcie prepnete potiahnutím troma prstami nahor a pridržaním."</string>
- <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Priblíženie"</string>
+ <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zväčšenie"</string>
<string name="user_switched" msgid="7249833311585228097">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Prepína sa na účet <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Prebieha odhlásenie používateľa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialógové okno napájania"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Skratka dostupnosti na obrazovke"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Výber skratky dostupnosti na obrazovke"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Skratka dostupnosti"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Odomknutie karty ICCID bolo úspešné."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Odomknutie karty IMPI bolo úspešné."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Odomknutie poskytovateľa služieb podmnožiny siete bolo úspešné."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b8bb8af..1258d2e 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -290,10 +290,10 @@
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Predstavitev za maloprodajo"</string>
<string name="notification_channel_usb" msgid="1528280969406244896">"Povezava USB"</string>
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikacija se izvaja"</string>
- <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacije, ki porabljajo energijo akumulatorja"</string>
- <string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> porablja energijo akumulatorja"</string>
- <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"Toliko aplikacij porablja energijo akumulatorja: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Dotaknite se za prikaz podrobnosti porabe akumulatorja in prenosa podatkov"</string>
+ <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacije, ki porabljajo energijo baterije"</string>
+ <string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> porablja energijo baterije"</string>
+ <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"Toliko aplikacij porablja energijo baterije: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+ <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Dotaknite se za prikaz podrobnosti porabe baterije in prenosa podatkov"</string>
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="8974401416068943888">"Varni način"</string>
<string name="android_system_label" msgid="5974767339591067210">"Sistem Android"</string>
@@ -380,7 +380,7 @@
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Prikaz aplikacije s prekrivanjem drugih aplikacij"</string>
<string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Ta aplikacija lahko prekrije druge aplikacije ali druge dele zaslona. To lahko vpliva na normalno delovanje aplikacije in na način prikaza drugih aplikacij."</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"izvajanje v ozadju"</string>
- <string name="permdesc_runInBackground" msgid="4344539472115495141">"Ta aplikacija se lahko izvaja tudi v ozadju, kar lahko privede do hitrejšega praznjenja akumulatorja."</string>
+ <string name="permdesc_runInBackground" msgid="4344539472115495141">"Ta aplikacija se lahko izvaja tudi v ozadju, kar lahko privede do hitrejšega praznjenja baterije."</string>
<string name="permlab_useDataInBackground" msgid="783415807623038947">"prenos podatkov v ozadju"</string>
<string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Ta aplikacija lahko prenaša podatke tudi v ozadju, kar lahko privede do večje porabe prenosa podatkov."</string>
<string name="permlab_persistentActivity" msgid="464970041740567970">"neprekinjeno izvajanje aplikacij"</string>
@@ -1430,8 +1430,8 @@
<string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Aplikaciji omogoča zahtevanje namestitve paketov."</string>
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"Zahteva za brisanje paketov"</string>
<string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Omogoča aplikaciji, da zahteva brisanje paketov."</string>
- <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"Dovoljenje za prezrtje optimizacij akumulatorja"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Aplikaciji dovoljuje, da vpraša za dovoljenje, ali naj prezre optimizacije akumulatorja."</string>
+ <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"Dovoljenje za prezrtje optimizacij baterije"</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Aplikaciji dovoljuje, da vpraša za dovoljenje, ali naj prezre optimizacije baterije."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tapnite dvakrat za nadzor povečave/pomanjšave"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Pripomočka ni bilo mogoče dodati."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Pojdi"</string>
@@ -2067,7 +2067,7 @@
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"prekriva druge aplikacije na zaslonu"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se bo morda izpraznila, preden jo običajno priključite na polnjenje"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo akumulatorja za podaljšanje časa delovanja akumulatorja"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo baterije za podaljšanje časa delovanja baterije"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo baterije"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Varčevanje z energijo baterije je izklopljeno"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija v telefonu je dovolj napolnjena. Funkcije niso več omejene."</string>
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Pogovorno okno o porabi energije"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Zaslonska bližnjica funkcij za ljudi s posebnimi potrebami"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Izbirnik zaslonske bližnjice funkcij za ljudi s posebnimi potrebami"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Bližnjica funkcij za ljudi s posebnimi potrebami"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Vrstica s podnapisi aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Odklepanje ICCID je uspelo."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Odklepanje IMPI je uspelo."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Odklepanje podnabora omrežja za ponudnika storitev je uspela."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 55f006e..84c5ab1 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1897,7 +1897,7 @@
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kontrollo për përditësim"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Ke mesazhe të reja"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Hap aplikacionin SMS për ta parë"</string>
- <string name="profile_encrypted_title" msgid="9001208667521266472">"Disa funksione mund të jenë të kufizuara"</string>
+ <string name="profile_encrypted_title" msgid="9001208667521266472">"Disa veçori mund të jenë të kufizuara"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"Profili i punës është i kyçur"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"Trokit për ta shkyçur profilin e punës"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"U lidh me <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogu i energjisë"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Shkurtorja e qasshmërisë në ekran"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Zgjedhësi i shkurtores së qasshmërisë në ekran"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Shkurtorja e qasshmërisë"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Shkyçja e ICCID ishte e suksesshme."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Shkyçja e IMPI ishte e suksesshme."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Shkyçja e ofruesit të shërbimit të nënrenditjes së rrjetit ishte e suksesshme."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d149e27..b083cb8 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2076,12 +2076,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дијалог напајања"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Закључани екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Снимак екрана"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Пречица за приступачност на екрану"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Алатка за бирање пречица за приступачност на екрану"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Пречица за приступачност"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2090,7 +2087,7 @@
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групна конверзација"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Лично"</string>
- <string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Пословно"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Лични приказ"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Приказ за посао"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Не можете да делите овај садржај помоћу апликација за посао"</string>
@@ -2215,4 +2212,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Откључавање ICCID-а је успело."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Откључавање IMPI-ја је успело."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Захтев за откључавање добављача услуге подскупа мреже је успео."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bb268cce..82ad594 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1794,8 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n•·inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”\n\n"<annotation id="url">"Läs mer"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n•·inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n• inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”\n\n"<annotation id="url">"Läs mer"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n• inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vill du aktivera Databesparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivera"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogruta för ström"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låsskärm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skärmdump"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Tillgänglighetsgenväg på skärmen"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Valfunktion för tillgänglighetsgenväg på skärmen"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Aktivera tillgänglighet snabbt"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Upplåst med ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Upplåst med IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Operatör upplåst för delnätverk."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4f9376c..2e60e1a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kidirisha cha Nishati"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Njia ya Mkato ya Ufikivu kwenye Skrini"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Kichagua Njia ya Mkato ya Ufikivu kwenye Skrini"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Njia ya Mkato ya Ufikivu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Imefungua kwa kutumia ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Imefungua kwa kutumia IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Imefungua kadi ya mtoa huduma ya mtandao mdogo."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 97b2afd..6c48c6f 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -693,7 +693,7 @@
<string name="policylab_setGlobalProxy" msgid="215332221188670221">"சாதன குளோபல் ப்ராக்ஸியை அமை"</string>
<string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"கொள்கை இயக்கப்பட்டிருக்கும்போது பயன்படுத்த வேண்டிய சாதன குளோபல் ப்ராக்ஸியை அமைக்கவும். சாதன உரிமையாளரால் மட்டுமே குளோபல் ப்ராக்ஸியை அமைக்க முடியும்."</string>
<string name="policylab_expirePassword" msgid="6015404400532459169">"திரைப் பூட்டு கடவுச்சொல் காலாவதி நேரத்தை அமை"</string>
- <string name="policydesc_expirePassword" msgid="9136524319325960675">"எந்த இடைவெளியில் திரைப் பூட்டின் கடவுச்சொல், பின் அல்லது வடிவம் மாற்றப்பட வேண்டும் என்பதை மாற்றும்."</string>
+ <string name="policydesc_expirePassword" msgid="9136524319325960675">"எந்த இடைவெளியில் திரைப் பூட்டின் கடவுச்சொல், பின் அல்லது பேட்டர்ன் மாற்றப்பட வேண்டும் என்பதை மாற்றும்."</string>
<string name="policylab_encryptedStorage" msgid="9012936958126670110">"சேமிப்பிட முறைமையாக்கலை அமை"</string>
<string name="policydesc_encryptedStorage" msgid="1102516950740375617">"சேமித்த ஆப்ஸ் டேட்டாவை முறைமையாக்கப்பட வேண்டும் என்பதைக் கோரலாம்."</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"கேமராக்களை முடக்கு"</string>
@@ -883,11 +883,11 @@
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"தடைநீக்கு"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"ஒலியை இயக்கு"</string>
<string name="lockscreen_sound_off_label" msgid="2331496559245450053">"ஒலியை முடக்கு"</string>
- <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"வடிவம் தொடங்கியது"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"வடிவம் அழிக்கப்பட்டது"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"பேட்டர்ன் தொடங்கியது"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"பேட்டர்ன் அழிக்கப்பட்டது"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6746676335293144163">"கலம் சேர்க்கப்பட்டது"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="2931364927622563465">"கலம் <xliff:g id="CELL_INDEX">%1$s</xliff:g> சேர்க்கப்பட்டது"</string>
- <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"வடிவம் நிறைவடைந்தது"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"பேட்டர்ன் நிறைவடைந்தது"</string>
<string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"வடிவப் பகுதி."</string>
<string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s. விட்ஜெட் %2$d / %3$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"விட்ஜெட்டைச் சேர்க்கவும்."</string>
@@ -904,7 +904,7 @@
<string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"விட்ஜெட் <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> நீக்கப்பட்டது."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"திறப்பதற்கான பகுதியை விவரிக்கவும்."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ஸ்லைடு மூலம் திறத்தல்."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"வடிவம் மூலம் திறத்தல்."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"பேட்டர்ன் மூலம் திறத்தல்."</string>
<string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"முகம் காட்டித் திறத்தல்."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin மூலம் திறத்தல்."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"சிம்மைத் திறக்கும் பின்."</string>
@@ -1576,7 +1576,7 @@
<string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", பாதுகாப்பானது"</string>
<string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"வடிவத்தை மறந்துவிட்டீர்களா"</string>
- <string name="kg_wrong_pattern" msgid="1342812634464179931">"தவறான வடிவம்"</string>
+ <string name="kg_wrong_pattern" msgid="1342812634464179931">"தவறான பேட்டர்ன்"</string>
<string name="kg_wrong_password" msgid="2384677900494439426">"தவறான கடவுச்சொல்"</string>
<string name="kg_wrong_pin" msgid="3680925703673166482">"தவறான பின்"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568">
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n\n•டார்க் தீமினை ஆன் செய்யும்\n•பின்னணி செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Hey Google” போன்ற பிற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n\n•டார்க் தீமினை ஆன் செய்யும்\n•பின்னணி செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Hey Google” போன்ற பிற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்"</string>
<string name="data_saver_description" msgid="4995164271550590517">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"இயக்கு"</string>
@@ -2044,17 +2042,13 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"பவர் உரையாடல்"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"திரையிலுள்ள அணுகல்தன்மை ஷார்ட்கட்"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"திரையிலுள்ள அணுகல்தன்மை ஷார்ட்கட்டிற்கான தேர்வி"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"அணுகல்தன்மை ஷார்ட்கட்"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸின் தலைப்புப் பட்டி."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"படம் அனுப்பப்பட்டது"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"உரையாடல்"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"குழு உரையாடல்"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
@@ -2184,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID அன்லாக் செயல்படுத்தப்பட்டது."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI அன்லாக் செயல்படுத்தப்பட்டது."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 1b1d43f..327d338 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1230,7 +1230,7 @@
<string name="volume_icon_description_media" msgid="4997633254078171233">"మీడియా వాల్యూమ్"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"నోటిఫికేషన్ వాల్యూమ్"</string>
<string name="ringtone_default" msgid="9118299121288174597">"డిఫాల్ట్ రింగ్టోన్"</string>
- <string name="ringtone_default_with_actual" msgid="2709686194556159773">"డిఫాల్ట్ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default_with_actual" msgid="2709686194556159773">"ఆటోమేటిక్ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="397111123930141876">"ఏదీ వద్దు"</string>
<string name="ringtone_picker_title" msgid="667342618626068253">"రింగ్టోన్లు"</string>
<string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"అలారం ధ్వనులు"</string>
@@ -1650,7 +1650,7 @@
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"పూర్తయింది"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"సత్వరమార్గాన్ని ఉపయోగించు"</string>
- <string name="color_inversion_feature_name" msgid="326050048927789012">"రంగుల మార్పిడి"</string>
+ <string name="color_inversion_feature_name" msgid="326050048927789012">"కలర్ మార్పిడి"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"రంగు సవరణ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"పవర్ డైలాగ్ను తెరువు"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్ను లాక్ చేయి"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్షాట్"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"స్క్రీన్పై ఉండే యాక్సెసిబిలిటీ షార్ట్కట్"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"స్క్రీన్పై ఉండే యాక్సెసిబిలిటీ షార్ట్కట్ల ఎంపిక సాధనం"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"యాక్సెసిబిలిటీ షార్ట్కట్"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> క్యాప్షన్ బార్."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID అన్లాక్ విజయవంతమైంది."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI అన్లాక్ విజయవంతమైంది."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"నెట్వర్క్ సబ్సెట్ సర్వీస్ ప్రొవైడర్ అన్లాక్ విజయవంతమైంది."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 80c7a59..90b5b65 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"กล่องโต้ตอบพลังงาน"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ทางลัดการช่วยเหลือพิเศษบนหน้าจอ"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ตัวเลือกทางลัดการช่วยเหลือพิเศษบนหน้าจอ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ทางลัดการช่วยเหลือพิเศษ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ปลดล็อก ICCID สำเร็จแล้ว"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"ปลดล็อก IMPI สำเร็จแล้ว"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"ปลดล็อกผู้ให้บริการในเครือข่ายย่อยสำเร็จแล้ว"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e1e9ca8..27e6b4d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog ng Power"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Shortcut ng Accessibility sa Screen"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Tagapili ng Shortcut ng Accessibility sa Screen"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Shortcut ng Accessibility"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Na-unlock na ang ICCID."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Na-unlock na ang IMPI."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Na-unlock na ang service provider ng subset ng Network."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 05984a0..3bade8e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Güç İletişim Kutusu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekran Erişilebilirlik Kısayolu"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekran Erişilebilirlik Kısayol Seçici"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Erişilebilirlik Kısayolu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID kilidi açıldı."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI kilidi açıldı."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Ağ alt kümesi servis sağlayıcı kilidi açıldı."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index fe373a1..087c8dd 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -857,7 +857,7 @@
<string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Зупинити"</string>
<string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Перемотати назад"</string>
<string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Перемотати вперед"</string>
- <string name="emergency_calls_only" msgid="3057351206678279851">"Лише аварійні виклики"</string>
+ <string name="emergency_calls_only" msgid="3057351206678279851">"Лише екстрені виклики"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Мережу заблок."</string>
<string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"SIM-карту заблоковано PUK."</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Перегляньте посібник користувача чи зверніться до служби підтримки."</string>
@@ -2110,12 +2110,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Відкрити вікно"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Екранний засіб спеціальних можливостей"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Вибір екранного засобу спеціальних можливостей"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Засіб спеціальних можливостей"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2249,4 +2246,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID розблоковано."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI розблоковано."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Постачальника послуг для підгрупи мереж розблоковано."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index f2ed250..3d0b66a 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -303,7 +303,7 @@
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS پیغامات بھیجیں اور دیکھیں"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"فائلز اور میڈیا"</string>
<string name="permgroupdesc_storage" msgid="6351503740613026600">"آپ کے آلہ پر تصاویر، میڈیا اور فائلوں تک رسائی حاصل کر سکتی ہیں"</string>
- <string name="permgrouplab_microphone" msgid="2480597427667420076">"مائکروفون"</string>
+ <string name="permgrouplab_microphone" msgid="2480597427667420076">"مائیکروفون"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"آڈیو ریکارڈ کریں"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"جسمانی سرگرمی"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"اپنی جسمانی سرگرمی تک رسائی حاصل کریں"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"پاور ڈائیلاگ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"آن اسکرین ایکسیسبیلٹی شارٹ کٹ"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"آن اسکرین ایکسیسبیلٹی شارٹ کٹ منتخب کنندہ"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ایکسیسبیلٹی کا شارٹ کٹ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی کیپشن بار۔"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID غیر مقفل ہو گیا۔"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI غیر مقفل ہو گیا۔"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"نیٹ ورک سب سیٹ کے خدمت کا فراہم کنندہ غیر مقفل ہو گیا۔"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index e072557..c82cc13 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -182,7 +182,7 @@
<item quantity="one">Sertifikat markazi sertifikati o‘rnatildi</item>
</plurals>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Noma‘lum uchinchi shaxslar tomonidan"</string>
- <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Ishchi profil administratori"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Ish profili administratori"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> tomonidan"</string>
<string name="work_profile_deleted" msgid="5891181538182009328">"Ichshi profil o‘chirildi"</string>
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Ishchi profilning administrator ilovasi yo‘q yoki buzilgan. Shuning uchun, ishchi profilingiz va unga aloqador ma’lumotlar o‘chirib tashlandi. Yordam olish uchun administratoringizga murojaat qiling."</string>
@@ -1854,7 +1854,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS talabi video chaqiruvga almashtirildi"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS talabi USSD talabiga almashtirildi"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yangi SS talabiga almashtirildi"</string>
- <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ishchi profil"</string>
+ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ish profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ogohlantirildi"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Yoyish"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Yig‘ish"</string>
@@ -1888,8 +1888,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ishlamayapti. Uning ishlashini <xliff:g id="APP_NAME_1">%2$s</xliff:g> cheklamoqda."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Batafsil"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Ilovani ishga tushirish"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Ishchi profil yoqilsinmi?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Ishchi ilovalar, bildirishnomalar, ma’lumotlar va boshqa ishchi profil imkoniyatlari yoqiladi"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Ish profili yoqilsinmi?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Ishga oid ilovalar, bildirishnomalar, ma’lumotlar va boshqa ish profili imkoniyatlari yoqiladi"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Yoqish"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
@@ -1898,7 +1898,7 @@
<string name="new_sms_notification_title" msgid="6528758221319927107">"Sizga yangi SMS keldi"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Ko‘rish uchun SMS ilovasini oching"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Ayrim funksiyalar ishlamasligi mumkin"</string>
- <string name="profile_encrypted_detail" msgid="5279730442756849055">"Ishchi profil yopiq"</string>
+ <string name="profile_encrypted_detail" msgid="5279730442756849055">"Ish profili yopiq"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"Qulfini ochish uchun bosing"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> qurilmasiga ulandi"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Fayllarni ko‘rish uchun bosing"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Quvvat muloqot oynasi"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran qulfi"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinshot"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranda tezkor ishga tushirish"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekranda tezkor ishga tushirishni tanlagich"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Tezkor ishga tushirish"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2067,7 +2064,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"AT administratoringiz bu turdagi kontentni shaxsiy profildagi ilovada ulashishni taqiqlagan"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Shaxsiy ilovalarda ochilmaydi"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"AT administratoringiz bu turdagi kontentni shaxsiy profildagi ilovada ochilishini taqiqlagan"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Ishchi profil pauzada"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Ish profili pauzada"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Yoqish"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Bu kontent bilan ishlay oladigan ishga oid ilovalar topilmadi"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Bu kontentni ocha oladigan ishga oid ilovalar topilmadi"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID qulfi ochildi."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI qulfi ochildi."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Aloqa operatori tarmoq qismi qulfdan chiqarilmadi."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8579414..27c0a71 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Tìm hiểu thêm"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Mở lại ứng dụng"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Bạn muốn bật hồ sơ công việc?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Ứng dụng công việc, thông báo, dữ liệu và các tính năng khác của hồ sơ công việc sẽ được bật"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Các ứng dụng công việc, thông báo, dữ liệu và các tính năng khác của hồ sơ công việc sẽ được bật"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bật"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Hộp thoại thao tác với nguồn"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Phím tắt hỗ trợ tiếp cận trên màn hình"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Bộ chọn phím tắt hỗ trợ tiếp cận trên màn hình"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Phím tắt hỗ trợ tiếp cận"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Mở khóa ICCID thành công."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Mở khóa IMPI thành công."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Mở khóa nhà cung cấp dịch vụ tập con của mạng thành công."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7b3ca76..eba34e1 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"电源对话框"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"屏幕上的无障碍功能快捷方式"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"屏幕上的无障碍功能快捷方式选择器"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"无障碍功能快捷方式"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID 解锁成功。"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI 解锁成功。"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"网络子集服务提供商解锁成功。"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 30a596a..795f561 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"電源對話框"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"螢幕無障礙功能捷徑"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"螢幕無障礙功能捷徑選擇器"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"無障礙功能捷徑"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID 解鎖成功。"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI 解鎖成功。"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"網絡子集服務供應商解鎖成功。"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ac5ebaa..44676d4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1889,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暫停應用程式"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作資料夾嗎?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟你的辦公應用程式、通知、資料和其他工作資料夾功能"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟你的工作應用程式、通知、資料和其他工作資料夾功能"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"開啟電源對話方塊"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"螢幕上的無障礙捷徑"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"螢幕上的無障礙捷徑選擇器"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"無障礙捷徑"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID 解鎖成功。"</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI 解鎖成功。"</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"網路子集服務供應商解鎖成功。"</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 32a31f7..e8a8b8d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2042,12 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Ibhokisi lamandla"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khiya isikrini"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Isithombe-skrini"</string>
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
- <skip />
- <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
- <skip />
- <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
- <skip />
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Isinqamuleli sokufinyeleleka kusikrini"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Isikhethi sesinqamuleli sokufinyeleleka kusikrini"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Isinqamuleli sokufinyeleleka"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2181,4 +2178,8 @@
<string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"Ukuvula i-ICCID kuphumelele."</string>
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"Ukuvula i-IMPI kuphumelele."</string>
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"Ukuvula I-subset yethiwekhi subset yomhlinzeki wesevisi kuphumelele."</string>
+ <string name="config_pdp_reject_dialog_title" msgid="4072057179246785727"></string>
+ <string name="config_pdp_reject_user_authentication_failed" msgid="4531693033885744689"></string>
+ <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b92bbd6..8a4676d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9230,4 +9230,7 @@
</declare-styleable>
<attr name="autoSizePresetSizes" />
+
+ <attr name="iconfactoryIconSize" format="dimension"/>
+ <attr name="iconfactoryBadgeSize" format="dimension"/>
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 831da6f..c413f8b 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -183,6 +183,10 @@
<color name="profile_badge_2">#ffff6d00</color><!-- Orange -->
<color name="profile_badge_3">#ff22f033</color><!-- Green -->
+ <color name="profile_badge_1_dark">#ff8ab4f8</color><!-- Blue 300-->
+ <color name="profile_badge_2_dark">#fffdd663</color><!-- Orange 300 -->
+ <color name="profile_badge_3_dark">#ff81c995</color><!-- Green 300 -->
+
<!-- Default instant app badge color -->
<color name="instant_app_badge">#ff757575</color><!-- Grey -->
@@ -227,5 +231,8 @@
<color name="resolver_empty_state_text">#FF202124</color>
<color name="resolver_empty_state_icon">#FF5F6368</color>
+ <!-- Color for personal app suspension notification button text and icon tint. -->
+ <color name="personal_apps_suspension_notification_color">#1A73E8</color>
+
<color name="conversation_important_highlight">#F9AB00</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fa4c25a..3730f05 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -44,6 +44,7 @@
<item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_camera</xliff:g></item>
@@ -59,7 +60,6 @@
<item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
</string-array>
<string translatable="false" name="status_bar_rotate">rotate</string>
@@ -3899,7 +3899,7 @@
<string name="config_managed_provisioning_package" translatable="false">com.android.managedprovisioning</string>
<!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
- <bool name="config_swipe_up_gesture_setting_available">false</bool>
+ <bool name="config_swipe_up_gesture_setting_available">true</bool>
<!-- Applications which are disabled unless matching a particular sku -->
<string-array name="config_disableApksUnlessMatchedSku_apk_list" translatable="false" />
@@ -4165,9 +4165,21 @@
and a second time clipped to the fill level to indicate charge -->
<bool name="config_batterymeterDualTone">false</bool>
- <!-- The default peak refresh rate for a given device. Change this value if you want to allow
- for higher refresh rates to be automatically used out of the box -->
- <integer name="config_defaultPeakRefreshRate">60</integer>
+ <!-- The default refresh rate for a given device. Change this value to set a higher default
+ refresh rate. If the hardware composer on the device supports display modes with a higher
+ refresh rate than the default value specified here, the framework may use those higher
+ refresh rate modes if an app chooses one by setting preferredDisplayModeId or calling
+ setFrameRate().
+ If a non-zero value is set for config_defaultPeakRefreshRate, then
+ config_defaultRefreshRate may be set to 0, in which case the value set for
+ config_defaultPeakRefreshRate will act as the default frame rate. -->
+ <integer name="config_defaultRefreshRate">60</integer>
+
+ <!-- The default peak refresh rate for a given device. Change this value if you want to prevent
+ the framework from using higher refresh rates, even if display modes with higher refresh
+ rates are available from hardware composer. Only has an effect if the value is
+ non-zero. -->
+ <integer name="config_defaultPeakRefreshRate">0</integer>
<!-- The display uses different gamma curves for different refresh rates. It's hard for panel
vendor to tune the curves to have exact same brightness for different refresh rate. So
@@ -4421,4 +4433,8 @@
<!-- Set to true to make assistant show in front of the dream/screensaver. -->
<bool name="config_assistantOnTopOfDream">false</bool>
+ <!-- pdp data retry for cause 29, 33 and 55 -->
+ <bool name="config_pdp_reject_enable_retry">false</bool>
+ <!-- pdp data reject retry delay in ms -->
+ <integer name="config_pdp_reject_retry_delay_ms">-1</integer>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bbe547b..c7ad5da 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -559,6 +559,10 @@
<dimen name="resolver_max_width">480dp</dimen>
+ <!-- Tile Stroke width -->
+ <dimen name="config_qsTileStrokeWidthActive">-1dp</dimen>
+ <dimen name="config_qsTileStrokeWidthInactive">-1dp</dimen>
+
<!-- Amount to reduce the size of the circular mask by (to compensate for
aliasing effects). This is only used on circular displays. -->
<dimen name="circular_display_mask_thickness">1px</dimen>
@@ -806,7 +810,8 @@
<dimen name="chooser_header_scroll_elevation">4dp</dimen>
<dimen name="chooser_max_collapsed_height">288dp</dimen>
<dimen name="chooser_direct_share_label_placeholder_max_width">72dp</dimen>
- <dimen name="chooser_icon_size">42dp</dimen>
+ <dimen name="chooser_icon_size">56dp</dimen>
+ <dimen name="chooser_badge_size">22dp</dimen>
<dimen name="resolver_icon_size">32dp</dimen>
<dimen name="resolver_button_bar_spacing">8dp</dimen>
<dimen name="resolver_badge_size">18dp</dimen>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index bd4c484..2c4f4c8 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -16,14 +16,7 @@
*/
-->
<resources>
- <dimen name="car_fullscreen_user_pod_icon_text_size">64sp</dimen>
- <dimen name="car_fullscreen_user_pod_width">243dp</dimen>
- <dimen name="car_fullscreen_user_pod_height">356dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
<dimen name="car_large_avatar_size">96dp</dimen>
-
-
<!-- Application Bar -->
<dimen name="car_app_bar_height">80dp</dimen>
<!-- Margin -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 51b23db..233f72ea 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -451,10 +451,14 @@
<string name="personal_apps_suspension_text">
Your personal apps are blocked until you turn on your work profile</string>
<!-- Notification text. This notification lets a user know that their apps will be blocked
- tomorrow due to a work policy from their IT admin, and that they need to turn on their work
- profile to prevent the apps from being blocked. [CHAR LIMIT=NONE] -->
- <string name="personal_apps_suspension_tomorrow_text">
- Your personal apps will be blocked tomorrow</string>
+ at a particular time due to a work policy from their IT admin, and that they need to turn on
+ their work profile to prevent the apps from being blocked. It also explains for how many
+ days the profile is allowed to be off and this number is at least 3. [CHAR LIMIT=NONE] -->
+ <string name="personal_apps_suspension_soon_text">
+ Personal apps will be blocked on <xliff:g id="date" example="May 29">%1$s</xliff:g> at
+ <xliff:g id="time" example="5:20 PM">%2$s</xliff:g>. Your work profile can\u2019t stay off
+ for more than <xliff:g id="number" example="3">%3$d</xliff:g> days.
+ </string>
<!-- Title for the button that turns work profile on. To be used in a notification
[CHAR LIMIT=NONE] -->
<string name="personal_apps_suspended_turn_profile_on">Turn on work profile</string>
@@ -1475,7 +1479,7 @@
<string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
<!-- Title shown when the system-provided biometric dialog is shown, asking the user to authenticate. [CHAR LIMIT=40] -->
- <string name="biometric_dialog_default_title">Verify it\u2018s you</string>
+ <string name="biometric_dialog_default_title">Verify it\u2019s you</string>
<!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
<string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
<!-- Message shown when biometric authentication was canceled by the user [CHAR LIMIT=50] -->
@@ -3595,31 +3599,37 @@
<!-- Notification body when new external media is detected [CHAR LIMIT=30] -->
<string name="ext_media_new_notification_title">New <xliff:g id="name" example="SD card">%s</xliff:g></string>
+ <!-- Automotive specific notification body when new external media is detected [CHAR LIMIT=30] -->
+ <string name="ext_media_new_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message">Tap to set up</string>
- <!-- Automotive specific notification body when new external media is detected. Empty because there is no fix action (b/151671685) [CHAR LIMIT=NONE] -->
- <string name="ext_media_new_notification_message" product="automotive"></string>
+ <!-- Automotive specific notification body when new external media is detected. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] -->
<string name="ext_media_ready_notification_message">For transferring photos and media</string>
<!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
<string name="ext_media_unmountable_notification_title">Issue with <xliff:g id="name" example="SD card">%s</xliff:g></string>
+ <!-- Automotive specific notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
+ <string name="ext_media_unmountable_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when external media is unmountable (corrupt) [CHAR LIMIT=NONE] -->
<string name="ext_media_unmountable_notification_message">Tap to fix</string>
<!-- TV-specific notification body when external media is unmountable (corrupt) [CHAR LIMIT=NONE] -->
<string name="ext_media_unmountable_notification_message" product="tv"><xliff:g id="name" example="SD card">%s</xliff:g> is corrupt. Select to fix.</string>
- <!-- Automotive specific notification body when external media is unmountable (corrupt). Empty because there is no fix action (b/151671685) [CHAR LIMIT=NONE] -->
- <string name="ext_media_unmountable_notification_message" product="automotive"></string>
+ <!-- Automotive specific notification body when external media is unmountable (corrupt) [CHAR LIMIT=NONE] -->
+ <string name="ext_media_unmountable_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification title when external media is unsupported [CHAR LIMIT=30] -->
<string name="ext_media_unsupported_notification_title">Unsupported <xliff:g id="name" example="SD card">%s</xliff:g></string>
+ <!-- Automotive specific notification title when external media is unsupported [CHAR LIMIT=30] -->
+ <string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
<!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message" product="tv">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Select to set up in a supported format.</string>
- <!-- Automotive specific notification body when external media is unsupported. No action is specified to fix (b/151671685) [CHAR LIMIT=NONE] -->
- <string name="ext_media_unsupported_notification_message" product="automotive">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>.</string>
+ <!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
+ <string name="ext_media_unsupported_notification_message" product="automotive">You may need to reformat the device</string>
<!-- Notification title when external media is unsafely removed [CHAR LIMIT=30] -->
<string name="ext_media_badremoval_notification_title"><xliff:g id="name" example="SD card">%s</xliff:g> unexpectedly removed</string>
@@ -4390,12 +4400,6 @@
<!-- Used in multiple service warning to list current features. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_multiple_service_list">\t• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
- <!-- Dialog title for dialog shown when the TalkBack shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_talkback_warning_title">Turn on TalkBack?</string>
-
- <!-- Message shown in dialog when user is in the process of enabling the TalkBack via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_talkback_warning">Holding down both volume keys for a few seconds turns on TalkBack, a screen reader that is helpful for people who are blind or have low vision. TalkBack completely changes how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility.</string>
-
<!-- Dialog title for dialog shown when this accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
@@ -5747,4 +5751,13 @@
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS">IMPI unlock successful.</string>
<!-- Success message displayed on SIM NS_SP Depersonalization panel [CHAR LIMIT=none] -->
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS">Network subset service provider unlock successful.</string>
+
+ <!-- pdp data reject dialog string for cause 29, 33 and 55 [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_dialog_title"></string>
+ <!-- pdp data reject dialog string for cause 29 (USER_AUTHENTICATION) [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_user_authentication_failed"></string>
+ <!-- pdp data reject dialog string for cause 33 (SERVICE_OPTION_NOT_SUBSCRIBED) [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_service_not_subscribed"></string>
+ <!-- pdp data reject dialog string for cause 55 (MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED) [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed"></string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index bcce1f0..f920083 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -248,12 +248,6 @@
<item name="windowExitAnimation">@anim/fast_fade_out</item>
</style>
- <!-- Window animations for screen savers. {@hide} -->
- <style name="Animation.Dream">
- <item name="windowEnterAnimation">@anim/slow_fade_in</item>
- <item name="windowExitAnimation">@anim/fast_fade_out</item>
- </style>
-
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBar">
<item name="textAppearance">?attr/textAppearanceSmall</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a82e778..a9e0b58 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -361,6 +361,8 @@
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="dimen" name="config_highResTaskSnapshotScale" />
<java-symbol type="dimen" name="config_lowResTaskSnapshotScale" />
+ <java-symbol type="dimen" name="config_qsTileStrokeWidthInactive" />
+ <java-symbol type="dimen" name="config_qsTileStrokeWidthActive" />
<java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" />
<java-symbol type="bool" name="config_hasRecents" />
<java-symbol type="string" name="config_recentsComponentName" />
@@ -1198,9 +1200,10 @@
<java-symbol type="string" name="location_changed_notification_title" />
<java-symbol type="string" name="location_changed_notification_text" />
<java-symbol type="string" name="personal_apps_suspension_title" />
- <java-symbol type="string" name="personal_apps_suspension_tomorrow_text" />
+ <java-symbol type="string" name="personal_apps_suspension_soon_text" />
<java-symbol type="string" name="personal_apps_suspension_text" />
<java-symbol type="string" name="personal_apps_suspended_turn_profile_on" />
+ <java-symbol type="string" name="notification_work_profile_content_description" />
<java-symbol type="string" name="factory_reset_warning" />
<java-symbol type="string" name="factory_reset_message" />
<java-symbol type="string" name="lockscreen_transport_play_description" />
@@ -1446,6 +1449,9 @@
<java-symbol type="color" name="profile_badge_1" />
<java-symbol type="color" name="profile_badge_2" />
<java-symbol type="color" name="profile_badge_3" />
+ <java-symbol type="color" name="profile_badge_1_dark" />
+ <java-symbol type="color" name="profile_badge_2_dark" />
+ <java-symbol type="color" name="profile_badge_3_dark" />
<java-symbol type="color" name="instant_app_badge" />
<java-symbol type="layout" name="action_bar_home" />
@@ -1580,7 +1586,6 @@
<java-symbol type="style" name="Animation.Tooltip" />
<java-symbol type="style" name="Animation.TypingFilter" />
<java-symbol type="style" name="Animation.TypingFilterRestore" />
- <java-symbol type="style" name="Animation.Dream" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.Alert" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
<java-symbol type="style" name="Theme.Dialog.Alert" />
@@ -1825,6 +1830,9 @@
<java-symbol type="anim" name="rotation_animation_jump_exit" />
<java-symbol type="anim" name="rotation_animation_xfade_exit" />
<java-symbol type="anim" name="rotation_animation_enter" />
+ <java-symbol type="anim" name="dream_activity_open_exit" />
+ <java-symbol type="anim" name="dream_activity_open_enter" />
+ <java-symbol type="anim" name="dream_activity_close_exit" />
<java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
@@ -2526,6 +2534,7 @@
<java-symbol type="style" name="TextAppearance.Material.TimePicker.TimeLabel" />
<java-symbol type="attr" name="seekBarPreferenceStyle" />
<java-symbol type="style" name="Theme.DeviceDefault.Resolver" />
+ <java-symbol type="style" name="Theme.DeviceDefault.Chooser" />
<java-symbol type="style" name="Theme.DeviceDefault.System" />
<java-symbol type="attr" name="preferenceActivityStyle" />
<java-symbol type="attr" name="preferenceFragmentStyle" />
@@ -2736,6 +2745,10 @@
<java-symbol type="id" name="chooser_row_text_option" />
<java-symbol type="dimen" name="chooser_row_text_option_translate" />
<java-symbol type="dimen" name="chooser_preview_image_max_dimen"/>
+ <java-symbol type="drawable" name="ic_chooser_group_arrow"/>
+ <java-symbol type="drawable" name="chooser_group_background"/>
+ <java-symbol type="drawable" name="ic_chooser_pin"/>
+ <java-symbol type="drawable" name="chooser_pinned_background"/>
<java-symbol type="integer" name="config_maxShortcutTargetsPerApp" />
<java-symbol type="layout" name="resolve_grid_item" />
<java-symbol type="id" name="day_picker_view_pager" />
@@ -3213,12 +3226,15 @@
<java-symbol type="integer" name="config_debugSystemServerPssThresholdBytes" />
<!-- Accessibility Shortcut -->
- <java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
- <java-symbol type="string" name="accessibility_shortcut_toogle_warning" />
+ <java-symbol type="string" name="accessibility_shortcut_single_service_warning_title" />
+ <java-symbol type="string" name="accessibility_shortcut_single_service_warning" />
+ <java-symbol type="string" name="accessibility_shortcut_multiple_service_warning_title" />
+ <java-symbol type="string" name="accessibility_shortcut_multiple_service_warning" />
+ <java-symbol type="string" name="accessibility_shortcut_multiple_service_list" />
+ <java-symbol type="string" name="accessibility_shortcut_on" />
+ <java-symbol type="string" name="accessibility_shortcut_off" />
<java-symbol type="string" name="accessibility_shortcut_enabling_service" />
<java-symbol type="string" name="accessibility_shortcut_disabling_service" />
- <java-symbol type="string" name="disable_accessibility_shortcut" />
- <java-symbol type="string" name="leave_accessibility_shortcut_on" />
<java-symbol type="string" name="color_inversion_feature_name" />
<java-symbol type="string" name="color_correction_feature_name" />
<java-symbol type="string" name="config_defaultAccessibilityService" />
@@ -3627,13 +3643,6 @@
<java-symbol type="color" name="car_card_dark" />
<java-symbol type="dimen" name="car_body1_size" />
<java-symbol type="dimen" name="car_padding_4" />
- <java-symbol type="dimen" name="car_fullscreen_user_pod_icon_text_size" />
- <java-symbol type="dimen" name="car_fullscreen_user_pod_image_avatar_height" />
- <java-symbol type="dimen" name="car_fullscreen_user_pod_image_avatar_width" />
- <java-symbol type="dimen" name="car_large_avatar_size" />
- <java-symbol type="layout" name="car_user_switching_dialog" />
- <java-symbol type="id" name="user_loading_avatar" />
- <java-symbol type="id" name="user_loading" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" />
<java-symbol type="string" name="battery_saver_description_with_learn_more" />
@@ -3765,6 +3774,7 @@
<java-symbol type="string" name="bluetooth_airplane_mode_toast" />
<!-- For high refresh rate displays -->
+ <java-symbol type="integer" name="config_defaultRefreshRate" />
<java-symbol type="integer" name="config_defaultPeakRefreshRate" />
<java-symbol type="integer" name="config_defaultRefreshRateInZone" />
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
@@ -3773,8 +3783,11 @@
<!-- For Auto-Brightness -->
<java-symbol type="string" name="config_displayLightSensorType" />
- <java-symbol type="drawable" name="iconfactory_adaptive_icon_drawable_wrapper"/>
<java-symbol type="dimen" name="notification_min_height" />
+
+ <java-symbol type="drawable" name="iconfactory_adaptive_icon_drawable_wrapper"/>
+ <java-symbol type="attr" name="iconfactoryIconSize"/>
+ <java-symbol type="attr" name="iconfactoryBadgeSize"/>
<java-symbol type="dimen" name="resolver_icon_size"/>
<java-symbol type="dimen" name="resolver_badge_size"/>
<java-symbol type="dimen" name="resolver_button_bar_spacing"/>
@@ -3783,6 +3796,7 @@
<java-symbol type="dimen" name="resolver_edge_margin"/>
<java-symbol type="dimen" name="resolver_elevation"/>
<java-symbol type="dimen" name="chooser_icon_size"/>
+ <java-symbol type="dimen" name="chooser_badge_size"/>
<!-- For DropBox -->
<java-symbol type="integer" name="config_dropboxLowPriorityBroadcastRateLimitPeriod" />
@@ -3999,4 +4013,14 @@
<java-symbol type="string" name="notification_channel_network_alerts" />
<java-symbol type="string" name="notification_channel_network_available" />
+ <java-symbol type="color" name="personal_apps_suspension_notification_color" />
+
+ <!-- For Pdn throttle feature -->
+ <java-symbol type="bool" name="config_pdp_reject_enable_retry" />
+ <java-symbol type="integer" name="config_pdp_reject_retry_delay_ms" />
+ <java-symbol type="string" name="config_pdp_reject_dialog_title" />
+ <java-symbol type="string" name="config_pdp_reject_user_authentication_failed" />
+ <java-symbol type="string" name="config_pdp_reject_service_not_subscribed" />
+ <java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 88f9fc2..6e2995d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -704,6 +704,7 @@
<style name="Theme.Dream">
<item name="windowBackground">@color/black</item>
<item name="windowDisablePreview">true</item>
+ <item name="windowActivityTransitions">true</item>
</style>
<!-- Default theme for dialog windows and activities (on API level 10 and lower),
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 81ec278..1afaf4f 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1680,6 +1680,8 @@
<item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
<item name="navigationBarColor">@android:color/transparent</item>
<item name="tabWidgetStyle">@style/Widget.DeviceDefault.Resolver.TabWidget</item>
+ <item name="iconfactoryIconSize">@dimen/resolver_icon_size</item>
+ <item name="iconfactoryBadgeSize">@dimen/resolver_badge_size</item>
</style>
<style name="Widget.DeviceDefault.Resolver.TabWidget" parent="Widget.DeviceDefault.TabWidget">
@@ -1694,6 +1696,11 @@
<item name="windowLightNavigationBar">true</item>
</style>
+ <style name="Theme.DeviceDefault.Chooser" parent="Theme.DeviceDefault.Resolver">
+ <item name="iconfactoryIconSize">@dimen/chooser_icon_size</item>
+ <item name="iconfactoryBadgeSize">@dimen/chooser_badge_size</item>
+ </style>
+
<style name="Animation.DeviceDefault.Activity.Resolver" parent="Animation.DeviceDefault.Activity">
<item name="activityOpenEnterAnimation">@anim/resolver_launch_anim</item>
<item name="taskOpenEnterAnimation">@anim/resolver_launch_anim</item>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 67a57aa..5c2841a 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1461,7 +1461,10 @@
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
</intent-filter>
</activity>
-
+ <activity android:name="android.window.WindowMetricsHelperTest$TestActivity"
+ android:resizeableActivity="true"
+ android:exported="true">
+ </activity>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a93dacf..000e870 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -20,6 +20,7 @@
import static android.content.Intent.ACTION_VIEW;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.Display.INVALID_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +30,7 @@
import static org.junit.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.IApplicationThread;
@@ -38,6 +40,7 @@
import android.app.servertransaction.ActivityRelaunchItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.StopActivityItem;
@@ -225,7 +228,7 @@
}
@Test
- public void testHandleActivityConfigurationChanged_PickNewerPendingConfiguration() {
+ public void testHandleActivityConfigurationChanged_SkipWhenNewerConfigurationPending() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
@@ -237,26 +240,91 @@
final ActivityThread activityThread = activity.getActivityThread();
- final Configuration pendingConfig = new Configuration();
- pendingConfig.orientation = orientation == ORIENTATION_LANDSCAPE
- ? ORIENTATION_PORTRAIT
- : ORIENTATION_LANDSCAPE;
- pendingConfig.seq = seq + 2;
+ final Configuration newerConfig = new Configuration();
+ newerConfig.orientation = orientation == ORIENTATION_LANDSCAPE
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ newerConfig.seq = seq + 2;
activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
- pendingConfig);
+ newerConfig);
- final Configuration newConfig = new Configuration();
- newConfig.orientation = orientation;
- newConfig.seq = seq + 1;
+ final Configuration olderConfig = new Configuration();
+ olderConfig.orientation = orientation;
+ olderConfig.seq = seq + 1;
activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
- newConfig, Display.INVALID_DISPLAY);
+ olderConfig, INVALID_DISPLAY);
+ assertEquals(numOfConfig, activity.mNumOfConfigChanges);
+ assertEquals(olderConfig.orientation, activity.mConfig.orientation);
+
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ newerConfig, INVALID_DISPLAY);
assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
- assertEquals(pendingConfig.orientation, activity.mConfig.orientation);
+ assertEquals(newerConfig.orientation, activity.mConfig.orientation);
});
}
@Test
+ public void testHandleActivityConfigurationChanged_EnsureUpdatesProcessedInOrder()
+ throws Exception {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ final ActivityThread activityThread = activity.getActivityThread();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final Configuration config = new Configuration();
+ config.seq = BASE_SEQ;
+ config.orientation = ORIENTATION_PORTRAIT;
+
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ config, INVALID_DISPLAY);
+ });
+
+ final IApplicationThread appThread = activityThread.getApplicationThread();
+ final int numOfConfig = activity.mNumOfConfigChanges;
+
+ final Configuration processConfigLandscape = new Configuration();
+ processConfigLandscape.windowConfiguration.setBounds(new Rect(0, 0, 100, 60));
+ processConfigLandscape.seq = BASE_SEQ + 1;
+
+ final Configuration activityConfigLandscape = new Configuration();
+ activityConfigLandscape.windowConfiguration.setBounds(new Rect(0, 0, 100, 50));
+ activityConfigLandscape.seq = BASE_SEQ + 2;
+
+ final Configuration processConfigPortrait = new Configuration();
+ processConfigPortrait.windowConfiguration.setBounds(new Rect(0, 0, 60, 100));
+ processConfigPortrait.seq = BASE_SEQ + 3;
+
+ final Configuration activityConfigPortrait = new Configuration();
+ activityConfigPortrait.windowConfiguration.setBounds(new Rect(0, 0, 50, 100));
+ activityConfigPortrait.seq = BASE_SEQ + 4;
+
+ activity.mConfigLatch = new CountDownLatch(1);
+ activity.mTestLatch = new CountDownLatch(1);
+
+ ClientTransaction transaction = newTransaction(activityThread, null);
+ transaction.addCallback(ConfigurationChangeItem.obtain(processConfigLandscape));
+ appThread.scheduleTransaction(transaction);
+
+ transaction = newTransaction(activityThread, activity.getActivityToken());
+ transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigLandscape));
+ transaction.addCallback(ConfigurationChangeItem.obtain(processConfigPortrait));
+ transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigPortrait));
+ appThread.scheduleTransaction(transaction);
+
+ activity.mTestLatch.await();
+ activity.mConfigLatch.countDown();
+
+ activity.mConfigLatch = null;
+ activity.mTestLatch = null;
+
+ // Check display metrics, bounds should match the portrait activity bounds.
+ final Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
+ assertEquals(activityConfigPortrait.windowConfiguration.getBounds(), bounds);
+
+ // Ensure that Activity#onConfigurationChanged() is only called once.
+ assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+ }
+
+ @Test
public void testHandleActivityConfigurationChanged_OnlyAppliesNewestConfiguration()
throws Exception {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
@@ -268,7 +336,7 @@
config.orientation = ORIENTATION_PORTRAIT;
activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
- config, Display.INVALID_DISPLAY);
+ config, INVALID_DISPLAY);
});
final int numOfConfig = activity.mNumOfConfigChanges;
@@ -504,7 +572,7 @@
config.orientation = ORIENTATION_PORTRAIT;
config.seq = seq;
activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
- Display.INVALID_DISPLAY);
+ INVALID_DISPLAY);
if (activity.mNumOfConfigChanges > numOfConfig) {
return config.seq;
@@ -514,7 +582,7 @@
config.orientation = ORIENTATION_LANDSCAPE;
config.seq = seq + 1;
activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
- Display.INVALID_DISPLAY);
+ INVALID_DISPLAY);
return config.seq;
}
@@ -572,8 +640,12 @@
}
private static ClientTransaction newTransaction(Activity activity) {
- final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
- return ClientTransaction.obtain(appThread, activity.getActivityToken());
+ return newTransaction(activity.getActivityThread(), activity.getActivityToken());
+ }
+
+ private static ClientTransaction newTransaction(ActivityThread activityThread,
+ @Nullable IBinder activityToken) {
+ return ClientTransaction.obtain(activityThread.getApplicationThread(), activityToken);
}
// Test activity
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 107fe3f..4654f63 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -63,7 +63,8 @@
@Test
public void testRecycleActivityConfigurationChangeItem() {
- ActivityConfigurationChangeItem emptyItem = ActivityConfigurationChangeItem.obtain(null);
+ ActivityConfigurationChangeItem emptyItem =
+ ActivityConfigurationChangeItem.obtain(Configuration.EMPTY);
ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config());
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
@@ -144,11 +145,12 @@
IBinder assistToken = new Binder();
LaunchActivityItem emptyItem = LaunchActivityItem.obtain(null, 0, null, null, null, null,
- null, null, 0, null, null, null, null, false, null, null);
+ null, null, 0, null, null, null, null, false, null, null, null);
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* isForward */, null /* profilerInfo */, assistToken);
+ true /* isForward */, null /* profilerInfo */, assistToken,
+ null /* fixedRotationAdjustments */);
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
@@ -158,7 +160,8 @@
LaunchActivityItem item2 = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* isForward */, null /* profilerInfo */, assistToken);
+ true /* isForward */, null /* profilerInfo */, assistToken,
+ null /* fixedRotationAdjustments */);
assertSame(item, item2);
assertFalse(item2.equals(emptyItem));
}
@@ -184,7 +187,7 @@
@Test
public void testRecycleMoveToDisplayItem() {
- MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, null);
+ MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, Configuration.EMPTY);
MoveToDisplayItem item = MoveToDisplayItem.obtain(4, config());
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index 09ea1b1..3c32c71 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -267,7 +267,7 @@
null /* voiceInteractor */, 0 /* procState */, null /* state */,
null /* persistentState */, null /* pendingResults */,
null /* pendingNewIntents */, false /* isForward */, null /* profilerInfo */,
- null /* assistToken*/));
+ null /* assistToken */, null /* fixedRotationAdjustments */));
launchTransaction.addCallback(launchItem);
mExecutor.execute(launchTransaction);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 47f9323..f11adef 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -52,6 +52,9 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
+import android.view.DisplayCutout;
+import android.view.Surface;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -187,11 +190,14 @@
bundle.putParcelable("data", new ParcelableData(1));
PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
+ FixedRotationAdjustments fixedRotationAdjustments = new FixedRotationAdjustments(
+ Surface.ROTATION_90, DisplayCutout.NO_CUTOUT);
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* isForward */, null /* profilerInfo */, new Binder());
+ true /* isForward */, null /* profilerInfo */, new Binder(),
+ fixedRotationAdjustments);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -340,6 +346,22 @@
assertTrue(transaction.equals(result));
}
+ @Test
+ public void testFixedRotationAdjustments() {
+ ClientTransaction transaction = ClientTransaction.obtain(new StubAppThread(),
+ null /* activityToken */);
+ transaction.addCallback(FixedRotationAdjustmentsItem.obtain(new Binder(),
+ new FixedRotationAdjustments(Surface.ROTATION_270, DisplayCutout.NO_CUTOUT)));
+
+ writeAndPrepareForReading(transaction);
+
+ // Read from parcel and assert
+ ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(transaction.hashCode(), result.hashCode());
+ assertTrue(transaction.equals(result));
+ }
+
/** Write to {@link #mParcel} and reset its position to prepare for reading from the start. */
private void writeAndPrepareForReading(Parcelable parcelable) {
parcelable.writeToParcel(mParcel, 0 /* flags */);
@@ -541,6 +563,11 @@
}
@Override
+ public void dumpCacheInfo(ParcelFileDescriptor parcelFileDescriptor, String[] strings)
+ throws RemoteException {
+ }
+
+ @Override
public void dumpProvider(ParcelFileDescriptor parcelFileDescriptor, IBinder iBinder,
String[] strings) throws RemoteException {
}
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
new file mode 100644
index 0000000..4d04a7a
--- /dev/null
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage;
+
+import static junit.framework.Assert.fail;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.ArrayUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+/**
+ * These tests verify that all fields defined in {@link UsageStats} and {@link UsageEvents.Event}
+ * are all known fields. This ensures that newly added fields or refactorings are accounted for in
+ * the usagestatsservice.proto and usagestatsservice_v2.proto files.
+ *
+ * Note: verification for {@link com.android.server.usage.IntervalStats} fields is located in
+ * {@link com.android.server.usage.IntervalStatsTests}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UsageStatsPersistenceTest {
+
+ // All fields in this list are defined in UsageStats and persisted - please ensure they're
+ // defined correctly in both usagestatsservice.proto and usagestatsservice_v2.proto
+ private static final String[] USAGESTATS_PERSISTED_FIELDS = {"mBeginTimeStamp", "mEndTimeStamp",
+ "mPackageName", "mPackageToken", "mLastEvent", "mAppLaunchCount", "mChooserCounts",
+ "mLastTimeUsed", "mTotalTimeInForeground", "mLastTimeForegroundServiceUsed",
+ "mTotalTimeForegroundServiceUsed", "mLastTimeVisible", "mTotalTimeVisible"};
+ // All fields in this list are defined in UsageStats but not persisted
+ private static final String[] USAGESTATS_IGNORED_FIELDS = {"CREATOR", "mActivities",
+ "mForegroundServices", "mLaunchCount", "mChooserCountsObfuscated"};
+
+ @Test
+ public void testUsageStatsFields() {
+ final UsageStats stats = new UsageStats();
+ final Field[] fields = stats.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ if (!(ArrayUtils.contains(USAGESTATS_PERSISTED_FIELDS, field.getName())
+ || ArrayUtils.contains(USAGESTATS_IGNORED_FIELDS, field.getName()))) {
+ fail("Found an unknown field: " + field.getName() + ". Please correctly update "
+ + "either USAGESTATS_PERSISTED_FIELDS or USAGESTATS_IGNORED_FIELDS.");
+ }
+ }
+ }
+
+ // All fields in this list are defined in UsageEvents.Event and persisted - please ensure
+ // they're defined correctly in both usagestatsservice.proto and usagestatsservice_v2.proto
+ private static final String[] USAGEEVENTS_PERSISTED_FIELDS = {"mPackage", "mPackageToken",
+ "mClass", "mClassToken", "mTimeStamp", "mFlags", "mEventType", "mConfiguration",
+ "mShortcutId", "mShortcutIdToken", "mBucketAndReason", "mInstanceId",
+ "mNotificationChannelId", "mNotificationChannelIdToken", "mTaskRootPackage",
+ "mTaskRootPackageToken", "mTaskRootClass", "mTaskRootClassToken", "mLocusId",
+ "mLocusIdToken"};
+ // All fields in this list are defined in UsageEvents.Event but not persisted
+ private static final String[] USAGEEVENTS_IGNORED_FIELDS = {"mAction", "mContentAnnotations",
+ "mContentType", "DEVICE_EVENT_PACKAGE_NAME", "FLAG_IS_PACKAGE_INSTANT_APP",
+ "VALID_FLAG_BITS", "UNASSIGNED_TOKEN", "MAX_EVENT_TYPE"};
+ // All fields in this list are final constants defining event types and not persisted
+ private static final String[] EVENT_TYPES = {"NONE", "ACTIVITY_DESTROYED", "ACTIVITY_PAUSED",
+ "ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "CHOOSER_ACTION", "CONFIGURATION_CHANGE",
+ "CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE", "DEVICE_SHUTDOWN",
+ "DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK", "FOREGROUND_SERVICE_START",
+ "FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN", "KEYGUARD_SHOWN", "LOCUS_ID_SET",
+ "MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND", "NOTIFICATION_INTERRUPTION",
+ "NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE", "SCREEN_INTERACTIVE",
+ "SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED", "SLICE_PINNED_PRIV",
+ "STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION", "USER_STOPPED",
+ "USER_UNLOCKED"};
+
+ @Test
+ public void testUsageEventsFields() {
+ final UsageEvents.Event event = new UsageEvents.Event();
+ final Field[] fields = event.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ final String name = field.getName();
+ if (!(ArrayUtils.contains(USAGEEVENTS_PERSISTED_FIELDS, name)
+ || ArrayUtils.contains(USAGEEVENTS_IGNORED_FIELDS, name)
+ || ArrayUtils.contains(EVENT_TYPES, name))) {
+ fail("Found an unknown field: " + name + ". Please correctly update either "
+ + "USAGEEVENTS_PERSISTED_FIELDS or USAGEEVENTS_IGNORED_FIELDS. If this "
+ + "field is a new event type, please update EVENT_TYPES instead.");
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 567552f..0490678 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -35,6 +35,9 @@
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
@@ -300,7 +303,8 @@
final Intent result = localReceiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_SUCCESS);
- assertEquals(expectedResult, status);
+ String statusMessage = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ assertEquals(statusMessage, expectedResult, status);
} catch (IllegalArgumentException | IOException | RemoteException e) {
Log.w(TAG, "Failed to install package; path=" + inPath, e);
fail("Failed to install package; path=" + inPath + ", e=" + e);
@@ -327,13 +331,14 @@
return Uri.fromFile(outFile);
}
- private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
+ private ParsingPackage parsePackage(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
- PackageParser packageParser = new PackageParser();
- File sourceFile = new File(archiveFilePath);
- PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, 0);
- packageParser = null;
- return pkg;
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ new File(archiveFilePath), 0 /*flags*/, false /*collectCertificates*/);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+ return result.getResult();
}
private boolean checkSd(long pkgLen) {
@@ -417,9 +422,9 @@
return INSTALL_LOC_ERR;
}
- private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) {
+ private void assertInstall(ParsingPackage pkg, int flags, int expInstallLocation) {
try {
- String pkgName = pkg.packageName;
+ String pkgName = pkg.getPackageName();
ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
assertNotNull(info);
assertEquals(pkgName, info.packageName);
@@ -565,20 +570,20 @@
class InstallParams {
Uri packageURI;
- PackageParser.Package pkg;
+ ParsingPackage pkg;
InstallParams(String outFileName, int rawResId) throws PackageParserException {
this.pkg = getParsedPackage(outFileName, rawResId);
- this.packageURI = Uri.fromFile(new File(pkg.codePath));
+ this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
}
- InstallParams(PackageParser.Package pkg) {
- this.packageURI = Uri.fromFile(new File(pkg.codePath));
+ InstallParams(ParsingPackage pkg) {
+ this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
this.pkg = pkg;
}
long getApkSize() {
- File file = new File(pkg.codePath);
+ File file = new File(pkg.getCodePath());
return file.length();
}
}
@@ -680,14 +685,12 @@
}
}
- private PackageParser.Package getParsedPackage(String outFileName, int rawResId)
- throws PackageParserException {
+ private ParsingPackage getParsedPackage(String outFileName, int rawResId) {
PackageManager pm = mContext.getPackageManager();
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
- return pkg;
+ return parsePackage(packageURI);
}
/*
@@ -698,15 +701,15 @@
private void installFromRawResource(InstallParams ip, int flags, boolean cleanUp, boolean fail,
int result, int expInstallLocation) throws Exception {
PackageManager pm = mContext.getPackageManager();
- PackageParser.Package pkg = ip.pkg;
+ ParsingPackage pkg = ip.pkg;
Uri packageURI = ip.packageURI;
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
// Make sure the package doesn't exist
try {
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName,
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES);
- GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
- invokeDeletePackage(pkg.packageName, 0, receiver);
+ GenericReceiver receiver = new DeleteReceiver(pkg.getPackageName());
+ invokeDeletePackage(pkg.getPackageName(), 0, receiver);
} catch (IllegalArgumentException | NameNotFoundException e) {
}
}
@@ -714,10 +717,10 @@
if (fail) {
invokeInstallPackageFail(packageURI, flags, result);
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
- assertNotInstalled(pkg.packageName);
+ assertNotInstalled(pkg.getPackageName());
}
} else {
- InstallReceiver receiver = new InstallReceiver(pkg.packageName);
+ InstallReceiver receiver = new InstallReceiver(pkg.getPackageName());
invokeInstallPackage(packageURI, flags, receiver, true);
// Verify installed information
assertInstall(pkg, flags, expInstallLocation);
@@ -818,15 +821,15 @@
Log.i(TAG, "replace=" + replace);
GenericReceiver receiver;
if (replace) {
- receiver = new ReplaceReceiver(ip.pkg.packageName);
+ receiver = new ReplaceReceiver(ip.pkg.getPackageName());
Log.i(TAG, "Creating replaceReceiver");
} else {
- receiver = new InstallReceiver(ip.pkg.packageName);
+ receiver = new InstallReceiver(ip.pkg.getPackageName());
}
try {
invokeInstallPackage(ip.packageURI, flags, receiver, true);
if (replace) {
- assertInstall(ip.pkg, flags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, flags, ip.pkg.getInstallLocation());
}
} finally {
cleanUpInstall(ip);
@@ -957,20 +960,20 @@
public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
InstallParams ip = sampleInstallFromRawResource(iFlags, false);
boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
try {
- assertTrue(invokeDeletePackage(ip.pkg.packageName, dFlags, receiver));
+ assertTrue(invokeDeletePackage(ip.pkg.getPackageName(), dFlags, receiver));
ApplicationInfo info = null;
Log.i(TAG, "okay4");
try {
- info = getPm().getApplicationInfo(ip.pkg.packageName,
+ info = getPm().getApplicationInfo(ip.pkg.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
info = null;
}
if (retainData) {
assertNotNull(info);
- assertEquals(info.packageName, ip.pkg.packageName);
+ assertEquals(info.packageName, ip.pkg.getPackageName());
} else {
assertNull(info);
}
@@ -998,9 +1001,9 @@
}
Runtime.getRuntime().gc();
try {
- cleanUpInstall(ip.pkg.packageName);
+ cleanUpInstall(ip.pkg.getPackageName());
} finally {
- File outFile = new File(ip.pkg.codePath);
+ File outFile = new File(ip.pkg.getCodePath());
if (outFile != null && outFile.exists()) {
outFile.delete();
}
@@ -1070,13 +1073,13 @@
InstallParams ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new ReplaceReceiver(ip.pkg.getPackageName());
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
InstallParams rp = installFromRawResource("install.apk", rApk,
replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- assertInstall(rp.pkg, replaceFlags, rp.pkg.installLocation);
+ assertInstall(rp.pkg, replaceFlags, rp.pkg.getInstallLocation());
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -1103,7 +1106,7 @@
InstallParams rp = installFromRawResource("install.apk", rApk,
replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- assertInstall(rp.pkg, replaceFlags, ip.pkg.installLocation);
+ assertInstall(rp.pkg, replaceFlags, ip.pkg.getInstallLocation());
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -1204,18 +1207,18 @@
// Install first
ip = installFromRawResource("install.apk", rawResId, installFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- ApplicationInfo oldAppInfo = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ ApplicationInfo oldAppInfo = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
if (fail) {
- assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
- ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ assertTrue(invokeMovePackageFail(ip.pkg.getPackageName(), moveFlags, result));
+ ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
assertNotNull(info);
assertEquals(oldAppInfo.flags, info.flags);
} else {
// Create receiver based on expRetCode
- MoveReceiver receiver = new MoveReceiver(ip.pkg.packageName);
- boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags, receiver);
+ MoveReceiver receiver = new MoveReceiver(ip.pkg.getPackageName());
+ boolean retCode = invokeMovePackage(ip.pkg.getPackageName(), moveFlags, receiver);
assertTrue(retCode);
- ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
assertNotNull("ApplicationInfo for recently installed application should exist",
info);
if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
@@ -1294,9 +1297,9 @@
ip = installFromRawResource("install.apk", R.raw.install, installFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
// Delete the package now retaining data.
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
- assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
+ assertTrue(invokeMovePackageFail(ip.pkg.getPackageName(), moveFlags, result));
} catch (Exception e) {
failStr(e);
} finally {
@@ -1712,7 +1715,7 @@
ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
// **: Upon installing package, are its permissions granted?
@@ -1722,15 +1725,15 @@
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_USED);
// **: Upon removing but not deleting, are permissions retained?
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
try {
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
} catch (Exception e) {
failStr(e);
}
@@ -1742,14 +1745,14 @@
ip = installFromRawResource("install.apk", iApk,
iFlags | PackageManager.INSTALL_REPLACE_EXISTING, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
assertPermissions(BASE_PERMISSIONS_USED);
// **: Upon deleting package, are all permissions removed?
try {
- invokeDeletePackage(ip.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), 0, receiver);
ip = null;
} catch (Exception e) {
failStr(e);
@@ -1759,9 +1762,9 @@
// **: Delete package using permissions; nothing to check here.
- GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.packageName);
+ GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.getPackageName());
try {
- invokeDeletePackage(ip2.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip2.pkg.getPackageName(), 0, receiver);
ip2 = null;
} catch (Exception e) {
failStr(e);
@@ -1772,7 +1775,7 @@
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_NOTUSED);
// **: Upon installing declaring package, are sig permissions granted
@@ -1781,7 +1784,7 @@
ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
assertPermissions(BASE_PERMISSIONS_SIGUSED);
@@ -1790,13 +1793,13 @@
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags | PackageManager.INSTALL_REPLACE_EXISTING, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_NOTUSED);
// **: Upon deleting package, are all permissions removed?
try {
- invokeDeletePackage(ip.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), 0, receiver);
ip = null;
} catch (Exception e) {
failStr(e);
@@ -1807,7 +1810,7 @@
// **: Delete package using permissions; nothing to check here.
try {
- invokeDeletePackage(ip2.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip2.pkg.getPackageName(), 0, receiver);
ip2 = null;
} catch (Exception e) {
failStr(e);
@@ -1862,7 +1865,7 @@
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
+ ParsingPackage pkg1 = getParsedPackage(apk1Name, apk1);
try {
InstallParams ip = installFromRawResource(apk1Name, apk1, 0, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
@@ -1873,7 +1876,7 @@
failStr(e.getMessage());
} finally {
if (cleanUp) {
- cleanUpInstall(pkg1.packageName);
+ cleanUpInstall(pkg1.getPackageName());
}
}
return null;
@@ -2460,16 +2463,16 @@
File outFile = new File(filesDir, apk2Name);
int rawResId = apk2;
Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
+ ParsingPackage pkg = parsePackage(packageURI);
try {
- getPi().uninstall(pkg.packageName,
+ getPi().uninstall(pkg.getPackageName(),
PackageManager.DELETE_ALL_USERS,
null /*statusReceiver*/);
} catch (IllegalArgumentException ignore) {
}
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip.pkg.packageName, pkg.packageName);
+ ip.pkg.getPackageName(), pkg.getPackageName());
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
cleanUpInstall(ip);
@@ -2530,13 +2533,13 @@
int retCode, int expMatchResult) throws Exception {
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
- PackageParser.Package pkg2 = getParsedPackage(apk2Name, apk2);
+ ParsingPackage pkg1 = getParsedPackage(apk1Name, apk1);
+ ParsingPackage pkg2 = getParsedPackage(apk2Name, apk2);
try {
// Clean up before testing first.
- cleanUpInstall(pkg1.packageName);
- cleanUpInstall(pkg2.packageName);
+ cleanUpInstall(pkg1.getPackageName());
+ cleanUpInstall(pkg2.getPackageName());
installFromRawResource(apk1Name, apk1, 0, false, false, -1,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
if (fail) {
@@ -2545,14 +2548,23 @@
} else {
installFromRawResource(apk2Name, apk2, 0, false, false, -1,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- int match = mContext.getPackageManager().checkSignatures(pkg1.packageName,
- pkg2.packageName);
- assertEquals(expMatchResult, match);
+ // TODO: All checkSignatures tests should return the same result regardless of
+ // querying by package name or uid; however if there are any edge cases where
+ // individual packages within a shareduid are compared with signatures that do not
+ // match the full lineage of the shareduid this method should be overloaded to
+ // accept the expected response for the uid query.
+ PackageManager pm = getPm();
+ int matchByName = pm.checkSignatures(pkg1.getPackageName(), pkg2.getPackageName());
+ int pkg1Uid = pm.getApplicationInfo(pkg1.getPackageName(), 0).uid;
+ int pkg2Uid = pm.getApplicationInfo(pkg2.getPackageName(), 0).uid;
+ int matchByUid = pm.checkSignatures(pkg1Uid, pkg2Uid);
+ assertEquals(expMatchResult, matchByName);
+ assertEquals(expMatchResult, matchByUid);
}
} finally {
if (cleanUp) {
- cleanUpInstall(pkg1.packageName);
- cleanUpInstall(pkg2.packageName);
+ cleanUpInstall(pkg1.getPackageName());
+ cleanUpInstall(pkg2.getPackageName());
}
}
}
@@ -2618,15 +2630,15 @@
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
PackageManager pm = mContext.getPackageManager();
// Delete app2
- PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
+ ParsingPackage pkg = getParsedPackage(apk2Name, apk2);
try {
- getPi().uninstall(
- pkg.packageName, PackageManager.DELETE_ALL_USERS, null /*statusReceiver*/);
+ getPi().uninstall(pkg.getPackageName(), PackageManager.DELETE_ALL_USERS,
+ null /*statusReceiver*/);
} catch (IllegalArgumentException ignore) {
}
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip1.pkg.packageName, pkg.packageName);
+ ip1.pkg.getPackageName(), pkg.getPackageName());
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
if (ip1 != null) {
@@ -2831,8 +2843,8 @@
PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
try {
// then, remove it, keeping it's data around
- final GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
+ final GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
final List<PackageInfo> packages = getPm().getInstalledPackages(flags);
assertNotNull("installed packages cannot be null", packages);
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index 4114b28..efcd458 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -259,4 +259,35 @@
expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
assertEquals(expectedConfig2, resources2.getConfiguration());
}
+
+ @SmallTest
+ public void testOverrideDisplayAdjustments() {
+ final int originalOverrideDensity = 200;
+ final int overrideDisplayDensity = 400;
+ final Binder token = new Binder();
+ final Configuration overrideConfig = new Configuration();
+ overrideConfig.densityDpi = originalOverrideDensity;
+ final Resources resources = mResourcesManager.createBaseTokenResources(
+ token, APP_ONE_RES_DIR, null /* splitResDirs */, null /* overlayDirs */,
+ null /* libDirs */, Display.DEFAULT_DISPLAY, overrideConfig,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* classLoader */,
+ null /* loaders */);
+
+ // Update the override.
+ boolean handled = mResourcesManager.overrideTokenDisplayAdjustments(token,
+ adjustments -> adjustments.getConfiguration().densityDpi = overrideDisplayDensity);
+
+ assertTrue(handled);
+ assertTrue(resources.hasOverrideDisplayAdjustments());
+ assertEquals(overrideDisplayDensity,
+ resources.getDisplayAdjustments().getConfiguration().densityDpi);
+
+ // Clear the override.
+ handled = mResourcesManager.overrideTokenDisplayAdjustments(token, null /* override */);
+
+ assertTrue(handled);
+ assertFalse(resources.hasOverrideDisplayAdjustments());
+ assertEquals(originalOverrideDensity,
+ resources.getDisplayAdjustments().getConfiguration().densityDpi);
+ }
}
diff --git a/core/tests/coretests/src/android/debug/AdbNotificationsTest.java b/core/tests/coretests/src/android/debug/AdbNotificationsTest.java
index 6c187ea..3496e2c 100644
--- a/core/tests/coretests/src/android/debug/AdbNotificationsTest.java
+++ b/core/tests/coretests/src/android/debug/AdbNotificationsTest.java
@@ -56,8 +56,11 @@
// Verify that the adb notification for usb connections has the correct text.
assertEquals(title, notification.extras.getCharSequence(Notification.EXTRA_TITLE, ""));
assertEquals(message, notification.extras.getCharSequence(Notification.EXTRA_TEXT, ""));
- // Verify the PendingIntent has an explicit intent (b/153356209).
- assertFalse(TextUtils.isEmpty(notification.contentIntent.getIntent().getPackage()));
+ // Verify the PendingIntent has an explicit intent (b/153356209), if there is a
+ // PendingIntent attached.
+ if (notification.contentIntent != null) {
+ assertFalse(TextUtils.isEmpty(notification.contentIntent.getIntent().getPackage()));
+ }
}
@Test
@@ -73,7 +76,10 @@
// Verify that the adb notification for usb connections has the correct text.
assertEquals(title, notification.extras.getCharSequence(Notification.EXTRA_TITLE, ""));
assertEquals(message, notification.extras.getCharSequence(Notification.EXTRA_TEXT, ""));
- // Verify the PendingIntent has an explicit intent (b/153356209).
- assertFalse(TextUtils.isEmpty(notification.contentIntent.getIntent().getPackage()));
+ // Verify the PendingIntent has an explicit intent (b/153356209), if there is a
+ // PendingIntent attached.
+ if (notification.contentIntent != null) {
+ assertFalse(TextUtils.isEmpty(notification.contentIntent.getIntent().getPackage()));
+ }
}
}
diff --git a/core/tests/coretests/src/android/hardware/display/OWNERS b/core/tests/coretests/src/android/hardware/display/OWNERS
new file mode 100644
index 0000000..9ca3910
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/display/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+santoscordon@google.com
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
new file mode 100644
index 0000000..1a28b73
--- /dev/null
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -0,0 +1,9 @@
+# Display
+per-file BrightnessLimit.java = michaelwr@google.com, santoscordon@google.com
+
+# Haptics
+per-file ExternalVibrationTest.java = michaelwr@google.com
+per-file VibrationEffectTest.java = michaelwr@google.com
+
+# Power
+per-file PowerManager*.java = michaelwr@google.com, santoscordon@google.com
diff --git a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
index afbf8db..2fc42e9 100644
--- a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
+++ b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
@@ -19,6 +19,9 @@
import static org.junit.Assert.assertEquals;
import android.content.res.Configuration;
+import android.graphics.Point;
+import android.util.DisplayMetrics;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -67,4 +70,38 @@
assertEquals(configuration, newAdjustments.getConfiguration());
}
+
+ @Test
+ public void testFixedRotationAdjustments() {
+ final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+ final int realRotation = Surface.ROTATION_0;
+ final int fixedRotation = Surface.ROTATION_90;
+
+ mDisplayAdjustments.setFixedRotationAdjustments(
+ new FixedRotationAdjustments(fixedRotation, null /* cutout */));
+
+ final int w = 1000;
+ final int h = 2000;
+ final Point size = new Point(w, h);
+ mDisplayAdjustments.adjustSize(size, realRotation);
+
+ assertEquals(fixedRotation, mDisplayAdjustments.getRotation(realRotation));
+ assertEquals(new Point(h, w), size);
+
+ final DisplayMetrics metrics = new DisplayMetrics();
+ metrics.xdpi = metrics.noncompatXdpi = w;
+ metrics.widthPixels = metrics.noncompatWidthPixels = w;
+ metrics.ydpi = metrics.noncompatYdpi = h;
+ metrics.heightPixels = metrics.noncompatHeightPixels = h;
+
+ final DisplayMetrics flippedMetrics = new DisplayMetrics();
+ flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = h;
+ flippedMetrics.widthPixels = flippedMetrics.noncompatWidthPixels = h;
+ flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = w;
+ flippedMetrics.heightPixels = flippedMetrics.noncompatHeightPixels = w;
+
+ mDisplayAdjustments.adjustMetrics(metrics, realRotation);
+
+ assertEquals(flippedMetrics, metrics);
+ }
}
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 164c372..bfcf52a 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -100,12 +100,12 @@
// test if setVisibility can show IME
mImeConsumer.onWindowFocusGained();
mImeConsumer.applyImeVisibility(true);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test if setVisibility can hide IME
mImeConsumer.applyImeVisibility(false);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 5f12bf0..8eca650 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -26,11 +26,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -98,8 +95,6 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- doNothing().when(mMockController).updateCompatSysUiVisibility(
- anyInt(), anyBoolean(), anyBoolean());
mTopLeash = new SurfaceControl.Builder(mSession)
.setName("testSurface")
.build();
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index cc85332..d4c2569 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -245,14 +245,14 @@
mController.applyImeVisibility(true /* setVisible */);
mController.show(Type.all());
// quickly jump to final state by cancelling it.
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.applyImeVisibility(false /* setVisible */);
mController.hide(Type.all());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -268,10 +268,10 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
mController.applyImeVisibility(true);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.applyImeVisibility(false);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.getSourceConsumer(ITYPE_IME).onWindowFocusLost();
});
@@ -291,7 +291,7 @@
mController.hide(types);
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
@@ -302,7 +302,7 @@
mController.show(types);
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -321,21 +321,21 @@
int types = Type.navigationBars() | Type.systemBars();
// test show select types.
mController.show(types);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test hide all
mController.hide(Type.all());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test single show
mController.show(Type.navigationBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -363,7 +363,7 @@
mController.hide(Type.systemBars());
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -372,7 +372,7 @@
mController.show(Type.systemBars());
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -383,7 +383,7 @@
mController.hide(Type.navigationBars());
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -391,7 +391,7 @@
mController.hide(Type.systemBars());
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -411,13 +411,13 @@
// show two at a time and hide one by one.
mController.show(types);
mController.hide(Type.navigationBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.hide(Type.systemBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -431,7 +431,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.hide(Type.statusBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
@@ -446,7 +446,7 @@
// Gaining control
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
});
@@ -468,7 +468,7 @@
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
});
@@ -489,7 +489,7 @@
mController.show(ime(), true /* fromIme */);
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
});
@@ -658,7 +658,7 @@
mController.getState().getSource(ITYPE_IME).getFrame());
assertNotEquals(new Rect(4, 5, 6, 7),
mController.getState().getSource(ITYPE_IME).getVisibleFrame());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertEquals(new Rect(0, 1, 2, 3),
mController.getState().getSource(ITYPE_IME).getFrame());
assertEquals(new Rect(4, 5, 6, 7),
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
new file mode 100644
index 0000000..a3a3e7c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -0,0 +1,4 @@
+# Input
+per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com
+per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com
+per-file VelocityTest.java = michaelwr@google.com, svv@google.com
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index 46e55fa..88ad279 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -24,6 +24,7 @@
import android.graphics.Rect;
import android.widget.TextView;
+import android.window.WindowMetricsHelper;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
@@ -55,7 +56,8 @@
// Specify start and end coordinates with respect to the window size.
final WindowManager wm = mScaleGestureActivity.getSystemService(WindowManager.class);
- final Rect windowBounds = wm.getCurrentWindowMetrics().getBounds();
+ final Rect windowBounds = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ wm.getCurrentWindowMetrics());
final int windowWidth = windowBounds.width();
final int windowHeight = windowBounds.height();
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index ecc3b4f..5c16772 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -28,29 +28,23 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static org.hamcrest.Matchers.equalTo;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.graphics.Insets;
-import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
/**
* Tests for {@link ViewRootImpl}
*
@@ -62,59 +56,18 @@
@RunWith(AndroidJUnit4.class)
public class ViewRootImplTest {
- private Context mContext;
- private ViewRootImplAccessor mViewRootImpl;
+ private ViewRootImpl mViewRootImpl;
@Before
public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final Context context = getInstrumentation().getTargetContext();
- InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mViewRootImpl = new ViewRootImplAccessor(
- new ViewRootImpl(mContext, mContext.getDisplayNoVerify()));
- });
- }
-
- @Test
- public void negativeInsets_areSetToZero() throws Exception {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mViewRootImpl.getAttachInfo().getContentInsets().set(-10, -20, -30 , -40);
- mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
- final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
-
- assertThat(insets.getSystemWindowInsets(), equalTo(Insets.NONE));
- assertThat(insets.getStableInsets(), equalTo(Insets.NONE));
- }
-
- @Test
- public void negativeInsets_areSetToZero_positiveAreLeftAsIs() throws Exception {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mViewRootImpl.getAttachInfo().getContentInsets().set(-10, 20, -30 , 40);
- mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
- final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
-
- assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(0, 20, 0, 40)));
- assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 0, 30, 0)));
- }
-
- @Test
- public void positiveInsets_areLeftAsIs() throws Exception {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mViewRootImpl.getAttachInfo().getContentInsets().set(10, 20, 30 , 40);
- mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
- final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
-
- assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(10, 20, 30, 40)));
- assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 20, 30, 40)));
+ getInstrumentation().runOnMainSync(() ->
+ mViewRootImpl = new ViewRootImpl(context, context.getDisplayNoVerify()));
}
@Test
public void adjustLayoutParamsForCompatibility_layoutFullscreen() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -125,8 +78,6 @@
@Test
public void adjustLayoutParamsForCompatibility_layoutInScreen() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.flags = FLAG_LAYOUT_IN_SCREEN;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -137,8 +88,6 @@
@Test
public void adjustLayoutParamsForCompatibility_layoutHideNavigation() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -149,28 +98,22 @@
@Test
public void adjustLayoutParamsForCompatibility_toast() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_TOAST);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(true, attrs.isFitInsetsIgnoringVisibility());
+ assertTrue(attrs.isFitInsetsIgnoringVisibility());
}
@Test
public void adjustLayoutParamsForCompatibility_systemAlert() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_SYSTEM_ALERT);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(true, attrs.isFitInsetsIgnoringVisibility());
+ assertTrue(attrs.isFitInsetsIgnoringVisibility());
}
@Test
public void adjustLayoutParamsForCompatibility_fitSystemBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -180,8 +123,6 @@
@Test
public void adjustLayoutParamsForCompatibility_noAdjustLayout() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
final int types = Type.all();
final int sides = Side.TOP | Side.LEFT;
@@ -201,11 +142,8 @@
@Test
public void adjustLayoutParamsForCompatibility_noAdjustAppearance() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- final ViewRootImpl viewRoot = mViewRootImpl.get();
- final WindowInsetsController controller = viewRoot.getInsetsController();
- final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes;
+ final WindowInsetsController controller = mViewRootImpl.getInsetsController();
+ final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
final int appearance = 0;
controller.setSystemBarsAppearance(appearance, 0xffffffff);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LOW_PROFILE
@@ -220,11 +158,8 @@
@Test
public void adjustLayoutParamsForCompatibility_noAdjustBehavior() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- final ViewRootImpl viewRoot = mViewRootImpl.get();
- final WindowInsetsController controller = viewRoot.getInsetsController();
- final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes;
+ final WindowInsetsController controller = mViewRootImpl.getInsetsController();
+ final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
final int behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
controller.setSystemBarsBehavior(behavior);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
@@ -234,59 +169,4 @@
// setSystemBarsBehavior.
assertEquals(behavior, controller.getSystemBarsBehavior());
}
-
- private static class ViewRootImplAccessor {
-
- private final ViewRootImpl mViewRootImpl;
-
- ViewRootImplAccessor(ViewRootImpl viewRootImpl) {
- mViewRootImpl = viewRootImpl;
- }
-
- public ViewRootImpl get() {
- return mViewRootImpl;
- }
-
- AttachInfoAccessor getAttachInfo() throws Exception {
- return new AttachInfoAccessor(
- getField(mViewRootImpl, ViewRootImpl.class.getDeclaredField("mAttachInfo")));
- }
-
- WindowInsets getWindowInsets(boolean forceConstruct) throws Exception {
- return (WindowInsets) invokeMethod(mViewRootImpl,
- ViewRootImpl.class.getDeclaredMethod("getWindowInsets", boolean.class),
- forceConstruct);
- }
-
- class AttachInfoAccessor {
-
- private final Class<?> mClass;
- private final Object mAttachInfo;
-
- AttachInfoAccessor(Object attachInfo) throws Exception {
- mAttachInfo = attachInfo;
- mClass = ViewRootImpl.class.getClassLoader().loadClass(
- "android.view.View$AttachInfo");
- }
-
- Rect getContentInsets() throws Exception {
- return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mContentInsets"));
- }
-
- Rect getStableInsets() throws Exception {
- return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mStableInsets"));
- }
- }
-
- private static Object getField(Object o, Field field) throws Exception {
- field.setAccessible(true);
- return field.get(o);
- }
-
- private static Object invokeMethod(Object o, Method method, Object... args)
- throws Exception {
- method.setAccessible(true);
- return method.invoke(o, args);
- }
- }
}
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index d51cc32..c5e69b6 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -23,6 +23,7 @@
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
+import android.window.WindowMetricsHelper;
/**
* A list of {@link InternalSelectionView}s paramatarized by the number of items,
@@ -111,7 +112,8 @@
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
+ mScreenHeight = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ getWindowManager().getCurrentWindowMetrics()).height();
Bundle extras = getIntent().getExtras();
if (extras != null) {
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index 5cedd13..5261fc9 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -24,6 +24,7 @@
import android.view.ViewConfiguration;
import android.widget.GridView;
import android.widget.gridview.GridVerticalSpacingStackFromBottom;
+import android.window.WindowMetricsHelper;
import androidx.test.filters.LargeTest;
import androidx.test.filters.MediumTest;
@@ -106,8 +107,8 @@
int firstTop = firstChild.getTop();
- int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getBounds()
- .height();
+ int windowHeight = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ mActivity.getWindowManager().getCurrentWindowMetrics()).height();
int distance = TouchUtils.dragViewBy(this, firstChild,
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, (int) (windowHeight * 0.75f));
diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
index 5cca766..62b93d6 100644
--- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
+++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -24,6 +24,7 @@
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
+import android.window.WindowMetricsHelper;
/**
* Most bodacious scenario yet!
@@ -65,8 +66,9 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final int desiredHeight =
- (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getBounds().height());
+ final int desiredHeight = (int) (0.8 * WindowMetricsHelper
+ .getBoundsExcludingNavigationBarAndCutout(
+ getWindowManager().getCurrentWindowMetrics()).height());
mLeftListView = new ListView(this);
mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
diff --git a/core/tests/coretests/src/android/window/WindowMetricsHelperTest.java b/core/tests/coretests/src/android/window/WindowMetricsHelperTest.java
new file mode 100644
index 0000000..921866b
--- /dev/null
+++ b/core/tests/coretests/src/android/window/WindowMetricsHelperTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.WindowMetrics;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link WindowMetricsHelper}
+ *
+ * <p>Build/Install/Run:
+ * atest FrameworksCoreTests:WindowMetricsHelperTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class WindowMetricsHelperTest {
+
+ @Rule
+ public ActivityTestRule<TestActivity> mActivityRule =
+ new ActivityTestRule<>(TestActivity.class);
+
+ @Test
+ public void testGetLegacySizeMatchesDisplayGetSize() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ Activity activity = mActivityRule.getActivity();
+ final WindowMetrics metrics = activity.getWindowManager().getCurrentWindowMetrics();
+ final Rect legacyBounds = WindowMetricsHelper
+ .getBoundsExcludingNavigationBarAndCutout(metrics);
+
+ final Point expectedSize = new Point();
+ activity.getDisplay().getSize(expectedSize);
+
+ assertEquals(expectedSize.x, legacyBounds.width());
+ assertEquals(expectedSize.y, legacyBounds.height());
+ });
+ }
+
+ public static class TestActivity extends Activity { }
+}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index b21504c..c17c36e 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -93,6 +93,7 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutControllerTest {
private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
+ private static final CharSequence PACKAGE_NAME_STRING = "Service name";
private static final String SERVICE_NAME_SUMMARY = "Summary";
private static final long VIBRATOR_PATTERN_1 = 100L;
private static final long VIBRATOR_PATTERN_2 = 150L;
@@ -150,6 +151,8 @@
new AccessibilityManager(mHandler, mAccessibilityManagerService, 0);
when(mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext))
.thenReturn(accessibilityManager);
+ when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE))
+ .thenReturn(accessibilityManager);
when(mFrameworkObjectProvider.getAlertDialogBuilder(mContext))
.thenReturn(mAlertDialogBuilder);
when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt()))
@@ -166,13 +169,13 @@
ResolveInfo resolveInfo = mock(ResolveInfo.class);
resolveInfo.serviceInfo = mock(ServiceInfo.class);
resolveInfo.serviceInfo.applicationInfo = mApplicationInfo;
- when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name");
+ when(resolveInfo.loadLabel(anyObject())).thenReturn(PACKAGE_NAME_STRING);
when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
when(mServiceInfo.getComponentName())
.thenReturn(ComponentName.unflattenFromString(SERVICE_NAME_STRING));
when(mServiceInfo.loadSummary(any())).thenReturn(SERVICE_NAME_SUMMARY);
- when(mAlertDialogBuilder.setTitle(anyInt())).thenReturn(mAlertDialogBuilder);
+ when(mAlertDialogBuilder.setTitle(anyObject())).thenReturn(mAlertDialogBuilder);
when(mAlertDialogBuilder.setCancelable(anyBoolean())).thenReturn(mAlertDialogBuilder);
when(mAlertDialogBuilder.setMessage(anyObject())).thenReturn(mAlertDialogBuilder);
when(mAlertDialogBuilder.setPositiveButton(anyInt(), anyObject()))
@@ -324,7 +327,8 @@
assertEquals(1, Settings.Secure.getInt(
mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0));
- verify(mResources).getString(R.string.accessibility_shortcut_toogle_warning);
+ verify(mResources).getString(
+ R.string.accessibility_shortcut_single_service_warning_title, PACKAGE_NAME_STRING);
verify(mAlertDialog).show();
verify(mAccessibilityManagerService, atLeastOnce()).getInstalledAccessibilityServiceList(
anyInt());
@@ -376,16 +380,20 @@
ArgumentCaptor<DialogInterface.OnClickListener> captor =
ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
- verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.disable_accessibility_shortcut),
+ verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.accessibility_shortcut_off),
captor.capture());
- // Call the button callback
- captor.getValue().onClick(null, 0);
+ // Call the button callback, if one exists
+ if (captor.getValue() != null) {
+ captor.getValue().onClick(null, 0);
+ }
assertTrue(TextUtils.isEmpty(
Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)));
+ assertEquals(0, Settings.Secure.getInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
}
@Test
- public void testClickingLeaveOnButtonInDialog_shouldLeaveShortcutReady() throws Exception {
+ public void testClickingTurnOnButtonInDialog_shouldLeaveShortcutReady() throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
@@ -393,8 +401,8 @@
ArgumentCaptor<DialogInterface.OnClickListener> captor =
ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
- verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.leave_accessibility_shortcut_on),
- captor.capture());
+ verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.accessibility_shortcut_on),
+ captor.capture());
// Call the button callback, if one exists
if (captor.getValue() != null) {
captor.getValue().onClick(null, 0);
@@ -402,7 +410,7 @@
assertEquals(SERVICE_NAME_STRING,
Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
assertEquals(1, Settings.Secure.getInt(
- mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 80fb358..dcecb5f 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -294,6 +294,60 @@
}
@Test
+ public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
+ Intent sendIntent = createSendTextIntent();
+
+ // create 12 unique app targets to ensure the app ranking row can be filled, otherwise
+ // targets will not stack
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(12);
+
+ // next create 4 targets in a single app that should be stacked into a single target
+ String packageName = "xxx.yyy";
+ String appName = "aaa";
+ ComponentName cn = new ComponentName(packageName, appName);
+ Intent intent = new Intent("fakeIntent");
+ List<ResolvedComponentInfo> infosToStack = new ArrayList<>();
+ for (int i = 0; i < 4; i++) {
+ ResolveInfo resolveInfo = ResolverDataProvider.createResolveInfo(i,
+ UserHandle.USER_CURRENT);
+ resolveInfo.activityInfo.applicationInfo.name = appName;
+ resolveInfo.activityInfo.applicationInfo.packageName = packageName;
+ resolveInfo.activityInfo.packageName = packageName;
+ resolveInfo.activityInfo.name = "ccc" + i;
+ infosToStack.add(new ResolvedComponentInfo(cn, intent, resolveInfo));
+ }
+ resolvedComponentInfos.addAll(infosToStack);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+ final ChooserWrapperActivity activity = mActivityRule
+ .launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+
+ // expect 12 unique targets + 1 group + 4 ranked app targets
+ assertThat(activity.getAdapter().getCount(), is(17));
+
+ ResolveInfo[] chosen = new ResolveInfo[1];
+ sOverrides.onSafelyStartCallback = targetInfo -> {
+ chosen[0] = targetInfo.getResolveInfo();
+ return true;
+ };
+
+ onView(withText(appName)).perform(click());
+ waitForIdle();
+
+ // clicking will launch a dialog to choose the activity within the app
+ onView(withText(appName)).check(matches(isDisplayed()));
+ int i = 0;
+ for (ResolvedComponentInfo rci: infosToStack) {
+ onView(withText("ccc" + i)).check(matches(isDisplayed()));
+ ++i;
+ }
+ }
+
+ @Test
public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1763,7 +1817,8 @@
Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
- Intent chooserIntent = createChooserIntent(new Intent[] {new Intent("action.fake")});
+ Intent chooserIntent = createChooserIntent(createSendTextIntent(),
+ new Intent[] {new Intent("action.fake")});
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
@@ -1796,7 +1851,7 @@
new Intent("action.fake1"),
new Intent("action.fake2")
};
- Intent chooserIntent = createChooserIntent(initialIntents);
+ Intent chooserIntent = createChooserIntent(createSendTextIntent(), initialIntents);
sOverrides.packageManager = mock(PackageManager.class);
when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt()))
.thenReturn(createFakeResolveInfo());
@@ -1809,12 +1864,101 @@
assertThat(activity.getWorkListAdapter().getCallerTargetCount(), is(0));
}
- private Intent createChooserIntent(Intent[] initialIntents) {
+ @Test
+ public void testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ int workProfileTargets = 4;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(workProfileTargets);
+ sOverrides.hasCrossProfileIntents = false;
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent[] initialIntents = {
+ new Intent("action.fake1"),
+ new Intent("action.fake2")
+ };
+ Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
+ sOverrides.packageManager = mock(PackageManager.class);
+ when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(createFakeResolveInfo());
+
+ final ChooserWrapperActivity activity = mActivityRule.launchActivity(chooserIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+
+ onView(withText(R.string.resolver_cant_access_work_apps))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent[] initialIntents = {
+ new Intent("action.fake1"),
+ new Intent("action.fake2")
+ };
+ Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
+ sOverrides.packageManager = mock(PackageManager.class);
+ when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(createFakeResolveInfo());
+
+ mActivityRule.launchActivity(chooserIntent);
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ onView(withText(R.string.resolver_no_work_apps_available_resolve))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testDeduplicateCallerTargetRankedTarget() {
+ // Create 4 ranked app targets.
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(4);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+ // Create caller target which is duplicate with one of app targets
+ Intent chooserIntent = createChooserIntent(createSendTextIntent(),
+ new Intent[] {new Intent("action.fake")});
+ sOverrides.packageManager = mock(PackageManager.class);
+ ResolveInfo ri = ResolverDataProvider.createResolveInfo(0,
+ UserHandle.USER_CURRENT);
+ when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(ri);
+ waitForIdle();
+
+ ChooserWrapperActivity activity = mActivityRule.launchActivity(chooserIntent);
+ waitForIdle();
+
+ // Total 4 targets (1 caller target, 3 ranked targets)
+ assertThat(activity.getAdapter().getCount(), is(4));
+ assertThat(activity.getAdapter().getCallerTargetCount(), is(1));
+ assertThat(activity.getAdapter().getRankedTargetCount(), is(3));
+ }
+
+ private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
Intent chooserIntent = new Intent();
chooserIntent.setAction(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
chooserIntent.putExtra(Intent.EXTRA_TITLE, "some title");
- chooserIntent.putExtra(Intent.EXTRA_INTENT, createSendTextIntent());
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
chooserIntent.setType("text/plain");
if (initialIntents != null) {
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, initialIntents);
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 0d52786..8bee1e5 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -43,6 +43,7 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.view.View;
@@ -827,6 +828,34 @@
assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0)));
}
+ @Test
+ public void testLayoutWithDefault_withWorkTab_neverShown() throws RemoteException {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+
+ // In this case we prefer the other profile and don't display anything about the last
+ // chosen activity.
+ Intent sendIntent = createSendImageIntent();
+ List<ResolvedComponentInfo> resolvedComponentInfos =
+ createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ when(sOverrides.resolverListController.getLastChosen())
+ .thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
+ waitForIdle();
+
+ // The other entry is filtered to the last used slot
+ assertThat(activity.getAdapter().hasFilteredItem(), is(false));
+ assertThat(activity.getAdapter().getCount(), is(2));
+ assertThat(activity.getAdapter().getPlaceholderCount(), is(2));
+ }
+
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 0390ac6..1cdc75a 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -225,7 +225,8 @@
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */,
- null /* profilerInfo */, mThread /* client */, null /* asssitToken */);
+ null /* profilerInfo */, mThread /* client */, null /* asssitToken */,
+ null /* fixedRotationAdjustments */);
}
@Override
diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp
index 2b38cca..a2fcef5 100644
--- a/core/tests/overlaytests/host/Android.bp
+++ b/core/tests/overlaytests/host/Android.bp
@@ -16,7 +16,7 @@
name: "OverlayHostTests",
srcs: ["src/**/*.java"],
libs: ["tradefed"],
- test_suites: ["device-tests"],
+ test_suites: ["general-tests"],
target_required: [
"OverlayHostTests_NonPlatformSignatureOverlay",
"OverlayHostTests_PlatformSignatureStaticOverlay",
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index dfb7a16..1b1a624 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -87,6 +87,13 @@
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.car.secondaryhome",
+ sub_dir: "permissions",
+ src: "com.android.car.secondaryhome.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.car.settings",
sub_dir: "permissions",
src: "com.android.car.settings.xml",
diff --git a/data/etc/car/com.android.car.secondaryhome.xml b/data/etc/car/com.android.car.secondaryhome.xml
index c74b86e..a8af906 100644
--- a/data/etc/car/com.android.car.secondaryhome.xml
+++ b/data/etc/car/com.android.car.secondaryhome.xml
@@ -20,5 +20,7 @@
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
<!-- Required to send notification to current user-->
<permission name="android.permission.MANAGE_USERS"/>
+ <!-- Required for CarNotificationLib -->
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 72827a9..a5a2221 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -16,6 +16,7 @@
-->
<permissions>
<privapp-permissions package="com.android.systemui">
+ <permission name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6af887d..9cd7cc6 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -197,6 +197,9 @@
<split-permission name="android.permission.WRITE_EXTERNAL_STORAGE">
<new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
</split-permission>
+ <split-permission name="android.permission.READ_PRIVILEGED_PHONE_STATE">
+ <new-permission name="android.permission.READ_PHONE_STATE" />
+ </split-permission>
<split-permission name="android.permission.READ_CONTACTS"
targetSdk="16">
<new-permission name="android.permission.READ_CALL_LOG" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0389639..bdb6bcc 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -324,6 +324,7 @@
<permission name="android.permission.MANAGE_ROLLBACKS"/>
<permission name="android.permission.MANAGE_USB"/>
<permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+ <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
diff --git a/data/keyboards/Vendor_28de_Product_1102.kl b/data/keyboards/Vendor_28de_Product_1102.kl
new file mode 100644
index 0000000..150a17a
--- /dev/null
+++ b/data/keyboards/Vendor_28de_Product_1102.kl
@@ -0,0 +1,74 @@
+# 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.
+
+#
+# Steam Controller - Model 1001 - USB
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 312 BUTTON_L2
+key 313 BUTTON_R2
+
+# Triggers.
+axis 0x15 LTRIGGER
+axis 0x14 RTRIGGER
+
+# Left and right stick.
+axis 0x00 X
+axis 0x01 Y
+
+# Right stick / mousepad
+axis 0x03 Z
+axis 0x04 RZ
+
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Dpad (clicks)
+key 544 DPAD_UP
+key 545 DPAD_DOWN
+key 546 DPAD_LEFT
+key 547 DPAD_RIGHT
+
+# Touching the dpad (light touch without pressing down)
+key 289 BUTTON_1
+# Touching the "right stick" / mousepad (light touch without pressing down)
+key 290 BUTTON_2
+
+# Pressing the large paddle on the back, left (linux BTN_WHEEL / BTN_GEAR_DOWN)
+key 336 BUTTON_3
+# Pressing the large paddle on the back, right (linux BTN_GEAR_UP)
+key 337 BUTTON_4
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Left arrow
+key 314 BUTTON_SELECT
+# Right arrow
+key 315 BUTTON_START
+
+# Steam key
+key 316 BUTTON_MODE
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index 016b855..098f4bf 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -20,6 +20,4 @@
plugins: [
"//external/dagger2:dagger2-auto-service",
],
-
- javacflags: ["-verbose"],
}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
new file mode 100644
index 0000000..48123ab
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.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.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.enclosingClass;
+import static com.google.errorprone.matchers.Matchers.hasAnnotation;
+import static com.google.errorprone.matchers.Matchers.instanceMethod;
+import static com.google.errorprone.matchers.Matchers.isSameType;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.throwStatement;
+import static com.google.errorprone.matchers.Matchers.variableType;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.CatchTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.CatchTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+
+import java.util.List;
+
+/**
+ * Apps making calls into the system server may end up persisting internal state
+ * or making security decisions based on the perceived success or failure of a
+ * call, or any default values returned. For this reason, we want to strongly
+ * throw when there was trouble with the transaction.
+ * <p>
+ * The rethrowFromSystemServer() method is the best-practice way of doing this
+ * correctly, so that we don't clutter logs with misleading stack traces, and
+ * this checker verifies that best-practice is used.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkRethrowFromSystem",
+ summary = "Verifies that system_server calls use rethrowFromSystemServer()",
+ severity = WARNING)
+public final class RethrowFromSystemChecker extends BugChecker implements CatchTreeMatcher {
+ private static final Matcher<Tree> INSIDE_MANAGER =
+ enclosingClass(hasAnnotation("android.annotation.SystemService"));
+ private static final Matcher<VariableTree> REMOTE_EXCEPTION = variableType(
+ isSameType("android.os.RemoteException"));
+ private static final Matcher<StatementTree> RETHROW_FROM_SYSTEM = throwStatement(
+ methodInvocation(instanceMethod().onExactClass("android.os.RemoteException")
+ .named("rethrowFromSystemServer")));
+
+ @Override
+ public Description matchCatch(CatchTree tree, VisitorState state) {
+ if (INSIDE_MANAGER.matches(tree, state)
+ && REMOTE_EXCEPTION.matches(tree.getParameter(), state)) {
+ final List<? extends StatementTree> statements = tree.getBlock().getStatements();
+ if (statements.size() != 1 || !RETHROW_FROM_SYSTEM.matches(statements.get(0), state)) {
+ return buildDescription(tree)
+ .setMessage("Must contain single "
+ + "'throw e.rethrowFromSystemServer()' statement")
+ .build();
+ }
+ }
+ return Description.NO_MATCH;
+ }
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
index 1ce816c..232cf3f 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
@@ -34,6 +34,27 @@
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree.Kind;
+/**
+ * Over the years we've had several obscure bugs related to how SDK level
+ * comparisons are performed, specifically during the window of time where we've
+ * started distributing the "frankenbuild" to developers.
+ * <p>
+ * Consider the case where a framework developer shipping release "R" wants to
+ * only grant a specific behavior to modern apps; they could write this in two
+ * different ways:
+ * <ol>
+ * <li>if (targetSdkVersion > Build.VERSION_CODES.Q) {
+ * <li>if (targetSdkVersion >= Build.VERSION_CODES.R) {
+ * </ol>
+ * The safer of these two options is (2), which will ensure that developers only
+ * get the behavior when <em>both</em> the app and the platform agree on the
+ * specific SDK level having shipped.
+ * <p>
+ * Consider the breakage that would happen with option (1) if we started
+ * shipping APKs that are based on the final R SDK, but are then installed on
+ * earlier preview releases which still consider R to be CUR_DEVELOPMENT; they'd
+ * risk crashing due to behaviors that were never part of the official R SDK.
+ */
@AutoService(BugChecker.class)
@BugPattern(
name = "AndroidFrameworkTargetSdk",
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 97b448a..c8f065a 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -70,9 +70,9 @@
* {@link Bitmap} objects.
*
* <p>To use it, first create a {@link Source Source} using one of the
- * {@code createSource} overloads. For example, to decode from a {@link File}, call
- * {@link #createSource(File)} and pass the result to {@link #decodeDrawable(Source)}
- * or {@link #decodeBitmap(Source)}:
+ * {@code createSource} overloads. For example, to decode from a {@link Uri}, call
+ * {@link #createSource(ContentResolver, Uri)} and pass the result to
+ * {@link #decodeDrawable(Source)} or {@link #decodeBitmap(Source)}:
*
* <pre class="prettyprint">
* File file = new File(...);
@@ -1032,7 +1032,11 @@
/**
* Create a new {@link Source Source} from a {@link java.io.File}.
- *
+ * <p>
+ * This method should only be used for files that you have direct access to;
+ * if you'd like to work with files hosted outside your app, use an API like
+ * {@link #createSource(Callable)} or
+ * {@link #createSource(ContentResolver, Uri)}.
* @return a new Source object, which can be passed to
* {@link #decodeDrawable decodeDrawable} or
* {@link #decodeBitmap decodeBitmap}.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
index c4f11a0..c61f1ed 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
@@ -30,6 +30,8 @@
import android.view.DisplayInfo;
import android.view.Surface;
+import androidx.annotation.Nullable;
+
/**
* Toolkit class for calculation of the display feature bounds within the window.
* NOTE: This sample implementation only works for Activity windows, because there is no public APIs
@@ -84,7 +86,7 @@
/** Transform rectangle from absolute coordinate space to the window coordinate space. */
static void transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken) {
- Rect windowRect = getWindowRect(windowToken);
+ Rect windowRect = getWindowBounds(windowToken);
if (windowRect == null) {
inOutRect.setEmpty();
return;
@@ -101,13 +103,12 @@
* Get the current window bounds in absolute coordinates.
* NOTE: Only works with Activity windows.
*/
- private static Rect getWindowRect(IBinder windowToken) {
+ @Nullable
+ private static Rect getWindowBounds(IBinder windowToken) {
Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
- final Rect windowRect = new Rect();
- if (activity != null) {
- activity.getWindow().getDecorView().getWindowDisplayFrame(windowRect);
- }
- return windowRect;
+ return activity != null
+ ? activity.getWindowManager().getCurrentWindowMetrics().getBounds()
+ : null;
}
/**
diff --git a/libs/hwui/jni/pdf/PdfEditor.cpp b/libs/hwui/jni/pdf/PdfEditor.cpp
index 828d6e3..e65921a 100644
--- a/libs/hwui/jni/pdf/PdfEditor.cpp
+++ b/libs/hwui/jni/pdf/PdfEditor.cpp
@@ -110,7 +110,7 @@
jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) {
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- FPDF_PAGE* page = (FPDF_PAGE*) FPDF_LoadPage(document, pageIndex);
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
if (!page) {
jniThrowException(env, "java/lang/IllegalStateException",
"cannot open page");
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 8d5acc6..24a6228 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -157,21 +157,7 @@
}
}
-static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) {
- int query_value;
- int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
- if (err != 0 || query_value < 0) {
- ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
- return;
- }
- auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
-
- int bufferCount = min_undequeued_buffers + 2 + extraBuffers;
- native_window_set_buffer_count(window, bufferCount);
-}
-
-bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
- uint32_t extraBuffers) {
+bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
@@ -189,7 +175,6 @@
if (mEglSurface != EGL_NO_SURFACE) {
const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
- setBufferCount(surface, extraBuffers);
return true;
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index fc6e114..fddd97f 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -45,8 +45,7 @@
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
- uint32_t extraBuffers) override;
+ bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 535a199..212a428 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -116,8 +116,7 @@
void SkiaVulkanPipeline::onStop() {}
-bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
- uint32_t extraBuffers) {
+bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
@@ -127,7 +126,7 @@
mRenderThread.requireVkContext();
mVkSurface =
mVkManager.createSurface(surface, mColorMode, mSurfaceColorSpace, mSurfaceColorType,
- mRenderThread.getGrContext(), extraBuffers);
+ mRenderThread.getGrContext(), 0);
}
return mVkSurface != nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index c8bf233..6268daa 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -42,8 +42,7 @@
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
- uint32_t extraBuffers) override;
+ bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 335bcdc..a362bd2 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -139,20 +139,22 @@
mAnimationContext->destroy();
}
+static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) {
+ int query_value;
+ int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
+ if (err != 0 || query_value < 0) {
+ ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
+ return;
+ }
+ auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+ int bufferCount = min_undequeued_buffers + 2 + extraBuffers;
+ native_window_set_buffer_count(window, bufferCount);
+}
+
void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
ATRACE_CALL();
- if (window) {
- mNativeSurface = std::make_unique<ReliableSurface>(window);
- mNativeSurface->init();
- if (enableTimeout) {
- // TODO: Fix error handling & re-shorten timeout
- ANativeWindow_setDequeueTimeout(window, 4000_ms);
- }
- } else {
- mNativeSurface = nullptr;
- }
-
if (mRenderAheadDepth == 0 && DeviceInfo::get()->getMaxRefreshRate() > 66.6f) {
mFixedRenderAhead = false;
mRenderAheadCapacity = 1;
@@ -161,9 +163,24 @@
mRenderAheadCapacity = mRenderAheadDepth;
}
+ if (window) {
+ mNativeSurface = std::make_unique<ReliableSurface>(window);
+ mNativeSurface->init();
+ if (enableTimeout) {
+ // TODO: Fix error handling & re-shorten timeout
+ ANativeWindow_setDequeueTimeout(window, 4000_ms);
+ }
+ mNativeSurface->setExtraBufferCount(mRenderAheadCapacity);
+ } else {
+ mNativeSurface = nullptr;
+ }
+
bool hasSurface = mRenderPipeline->setSurface(
- mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior,
- mRenderAheadCapacity);
+ mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
+
+ if (mNativeSurface && !mNativeSurface->didSetExtraBuffers()) {
+ setBufferCount(mNativeSurface->getNativeWindow(), mRenderAheadCapacity);
+ }
mFrameNumber = -1;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index ba0d64c..c3c2286 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -66,8 +66,7 @@
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
- virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior,
- uint32_t extraBuffers) = 0;
+ virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
virtual bool isContextReady() = 0;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index 8a0b4e8..dcf1fc1 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -19,6 +19,7 @@
#include <log/log_main.h>
#include <private/android/AHardwareBufferHelpers.h>
// TODO: this should be including apex instead.
+#include <system/window.h>
#include <vndk/window.h>
namespace android::uirenderer::renderthread {
@@ -44,6 +45,7 @@
ANativeWindow_setDequeueBufferInterceptor(mWindow, nullptr, nullptr);
ANativeWindow_setQueueBufferInterceptor(mWindow, nullptr, nullptr);
ANativeWindow_setPerformInterceptor(mWindow, nullptr, nullptr);
+ ANativeWindow_setQueryInterceptor(mWindow, nullptr, nullptr);
ANativeWindow_release(mWindow);
}
@@ -63,6 +65,10 @@
result = ANativeWindow_setPerformInterceptor(mWindow, hook_perform, this);
LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
result);
+
+ result = ANativeWindow_setQueryInterceptor(mWindow, hook_query, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set query interceptor: error = %d",
+ result);
}
int ReliableSurface::reserveNext() {
@@ -249,9 +255,29 @@
case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
rs->mFormat = static_cast<AHardwareBuffer_Format>(va_arg(args, int32_t));
break;
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ size_t bufferCount = va_arg(args, size_t);
+ if (bufferCount >= rs->mExpectedBufferCount) {
+ rs->mDidSetExtraBuffers = true;
+ } else {
+ ALOGD("HOOK FAILED! Expected %zd got = %zd", rs->mExpectedBufferCount, bufferCount);
+ }
+ break;
}
}
return result;
}
+int ReliableSurface::hook_query(const ANativeWindow *window, ANativeWindow_queryFn query,
+ void *data, int what, int *value) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ int result = query(window, what, value);
+ if (what == ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS && result == OK) {
+ std::lock_guard _lock{rs->mMutex};
+ *value += rs->mExtraBuffers;
+ rs->mExpectedBufferCount = *value + 2;
+ }
+ return result;
+}
+
}; // namespace android::uirenderer::renderthread
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index 58cd067..f699eb1 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/unique_fd.h>
+#include <system/window.h>
#include <apex/window.h>
#include <utils/Errors.h>
#include <utils/Macros.h>
@@ -49,6 +50,16 @@
return ret;
}
+ void setExtraBufferCount(size_t extraBuffers) {
+ std::lock_guard _lock{mMutex};
+ mExtraBuffers = extraBuffers;
+ }
+
+ bool didSetExtraBuffers() const {
+ std::lock_guard _lock{mMutex};
+ return mDidSetExtraBuffers;
+ }
+
private:
ANativeWindow* mWindow;
@@ -62,6 +73,9 @@
base::unique_fd mReservedFenceFd;
bool mHasDequeuedBuffer = false;
int mBufferQueueState = OK;
+ size_t mExtraBuffers = 0;
+ size_t mExpectedBufferCount = 0;
+ bool mDidSetExtraBuffers = false;
bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const;
ANativeWindowBuffer* acquireFallbackBuffer(int error);
@@ -81,6 +95,8 @@
static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data,
int operation, va_list args);
+ static int hook_query(const ANativeWindow* window, ANativeWindow_queryFn query, void* data,
+ int what, int* value);
};
}; // namespace android::uirenderer::renderthread
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 1208062..e7a889d 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -398,7 +398,7 @@
auto surface = context.surface();
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
EXPECT_FALSE(pipeline->isSurfaceReady());
- EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, 0));
+ EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default));
EXPECT_TRUE(pipeline->isSurfaceReady());
renderThread.destroyRenderingContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 412b43e..a112bdd0 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2954,10 +2954,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.unregisterGnssStatusCallback(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.unregisterGnssStatusCallback(mListenerTransport);
+ mListenerTransport = null;
+ }
}
private class GnssStatusListener extends IGnssStatusListener.Stub {
@@ -3020,10 +3020,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssMeasurementsListener(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssMeasurementsListener(mListenerTransport);
+ mListenerTransport = null;
+ }
}
@Override
@@ -3073,10 +3073,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssNavigationMessageListener(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssNavigationMessageListener(mListenerTransport);
+ mListenerTransport = null;
+ }
}
private class GnssNavigationMessageListener extends IGnssNavigationMessageListener.Stub {
@@ -3114,10 +3114,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssAntennaInfoListener(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssAntennaInfoListener(mListenerTransport);
+ mListenerTransport = null;
+ }
}
private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub {
@@ -3151,10 +3151,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssBatchingCallback();
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssBatchingCallback();
+ mListenerTransport = null;
+ }
}
private class BatchedLocationCallback extends IBatchedLocationCallback.Stub {
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 6b0e17d..2cca669 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -455,8 +455,7 @@
* may be an empty array if no encapsulation modes are supported.
*/
public @NonNull @AudioTrack.EncapsulationMode int[] getEncapsulationModes() {
- // Implement a getter in r-dev or r-tv-dev as needed.
- return new int[0]; // be careful of returning a copy of any internal data.
+ return mPort.encapsulationModes();
}
/**
@@ -474,8 +473,7 @@
* may be an empty array if no metadata types are supported.
*/
public @NonNull @AudioTrack.EncapsulationMetadataType int[] getEncapsulationMetadataTypes() {
- // Implement a getter in r-dev or r-tv-dev as needed.
- return new int[0]; // be careful of returning a copy of any internal data.
+ return mPort.encapsulationMetadataTypes();
}
/**
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index 51909db..42d0f0c 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -16,8 +16,11 @@
package android.media;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
+import java.util.Arrays;
+
/**
* The AudioDevicePort is a specialized type of AudioPort
* describing an input (e.g microphone) or output device (e.g speaker)
@@ -35,17 +38,22 @@
private final int mType;
private final String mAddress;
+ private final int[] mEncapsulationModes;
+ private final int[] mEncapsulationMetadataTypes;
@UnsupportedAppUsage
AudioDevicePort(AudioHandle handle, String deviceName,
int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
- int[] formats, AudioGain[] gains, int type, String address) {
+ int[] formats, AudioGain[] gains, int type, String address, int[] encapsulationModes,
+ @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes) {
super(handle,
(AudioManager.isInputDevice(type) == true) ?
AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains);
mType = type;
mAddress = address;
+ mEncapsulationModes = encapsulationModes;
+ mEncapsulationMetadataTypes = encapsulationMetadataTypes;
}
/**
@@ -72,6 +80,31 @@
}
/**
+ * Get supported encapsulation modes.
+ */
+ public @NonNull @AudioTrack.EncapsulationMode int[] encapsulationModes() {
+ if (mEncapsulationModes == null) {
+ return new int[0];
+ }
+ return Arrays.stream(mEncapsulationModes).boxed()
+ .filter(mode -> mode != AudioTrack.ENCAPSULATION_MODE_HANDLE)
+ .mapToInt(Integer::intValue).toArray();
+ }
+
+ /**
+ * Get supported encapsulation metadata types.
+ */
+ public @NonNull @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes() {
+ if (mEncapsulationMetadataTypes == null) {
+ return new int[0];
+ }
+ int[] encapsulationMetadataTypes = new int[mEncapsulationMetadataTypes.length];
+ System.arraycopy(mEncapsulationMetadataTypes, 0,
+ encapsulationMetadataTypes, 0, mEncapsulationMetadataTypes.length);
+ return encapsulationMetadataTypes;
+ }
+
+ /**
* Build a specific configuration of this audio device port for use by methods
* like AudioManager.connectAudioPatch().
*/
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8ea6883..ea7a556 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1505,7 +1505,7 @@
public void setSpeakerphoneOn(boolean on){
final IAudioService service = getService();
try {
- service.setSpeakerphoneOn(on);
+ service.setSpeakerphoneOn(mICallBack, on);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 98c2d7f..357c333 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -16,6 +16,7 @@
package android.media;
import android.util.IntArray;
+
import com.android.server.LocalServices;
/**
@@ -48,6 +49,18 @@
public abstract void setAccessibilityServiceUids(IntArray uids);
+ /**
+ * Called by {@link com.android.server.inputmethod.InputMethodManagerService} to notify the UID
+ * of the currently used {@link android.inputmethodservice.InputMethodService}.
+ *
+ * <p>The caller is expected to take care of any performance implications, e.g. by using a
+ * background thread to call this method.</p>
+ *
+ * @param uid UID of the currently used {@link android.inputmethodservice.InputMethodService}.
+ * {@link android.os.Process#INVALID_UID} if no IME is active.
+ */
+ public abstract void setInputMethodServiceUid(int uid);
+
public interface RingerModeDelegate {
/** Called when external ringer mode is evaluated, returns the new internal ringer mode */
int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index c91ff0d..ff9fd41 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -166,10 +166,25 @@
*
* A Boolean value which is true if Atmos is present in an E-AC3 stream.
*/
+
+ // Since Boolean isn't handled by Parceling, we translate
+ // internally to KEY_HAS_ATMOS when sending through JNI.
+ // Consider deprecating this key for KEY_HAS_ATMOS in the future.
+ //
@NonNull public static final Key<Boolean> KEY_ATMOS_PRESENT =
createKey("atmos-present", Boolean.class);
/**
+ * A key representing the presence of Atmos in an E-AC3 stream.
+ *
+ * An Integer value which is nonzero if Atmos is present in an E-AC3 stream.
+ * The integer representation is used for communication to the native side.
+ * @hide
+ */
+ @NonNull public static final Key<Integer> KEY_HAS_ATMOS =
+ createKey("has-atmos", Integer.class);
+
+ /**
* A key representing the audio encoding used for the stream.
* This is the same encoding used in {@link AudioFormat#getEncoding()}.
*
@@ -731,6 +746,15 @@
Log.e(TAG, "Failed to unpack value for map");
return null;
}
+
+ // Special handling of KEY_ATMOS_PRESENT.
+ if (key.equals(Format.KEY_HAS_ATMOS.getName())
+ && value.first == Format.KEY_HAS_ATMOS.getValueClass()) {
+ ret.set(Format.KEY_ATMOS_PRESENT,
+ (Boolean) ((int) value.second != 0)); // Translate Integer to Boolean
+ continue; // Should we store both keys in the java table?
+ }
+
ret.set(createKey(key, value.first), value.first.cast(value.second));
}
return ret;
@@ -746,11 +770,19 @@
return false;
}
for (Key<?> key : obj.keySet()) {
+ Object value = obj.get(key);
+
+ // Special handling of KEY_ATMOS_PRESENT.
+ if (key == Format.KEY_ATMOS_PRESENT) {
+ key = Format.KEY_HAS_ATMOS;
+ value = (Integer) ((boolean) value ? 1 : 0); // Translate Boolean to Integer
+ }
+
if (!strDataPackage.pack(output, key.getName())) {
Log.i(TAG, "Failed to pack key: " + key.getName());
return false;
}
- if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), obj.get(key)))) {
+ if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), value))) {
Log.i(TAG, "Failed to pack value: " + obj.get(key));
return false;
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e3b67f8..8137275 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -150,7 +150,7 @@
oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
- void setSpeakerphoneOn(boolean on);
+ void setSpeakerphoneOn(IBinder cb, boolean on);
boolean isSpeakerphoneOn();
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index bbd7399..54675d0 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -321,6 +321,21 @@
@UnsupportedAppUsage
private long mNativeObject;
+ private String convertMuxerStateCodeToString(int aState) {
+ switch (aState) {
+ case MUXER_STATE_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case MUXER_STATE_INITIALIZED:
+ return "INITIALIZED";
+ case MUXER_STATE_STARTED:
+ return "STARTED";
+ case MUXER_STATE_STOPPED:
+ return "STOPPED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
/**
* Constructor.
* Creates a media muxer that writes to the specified path.
@@ -397,7 +412,7 @@
nativeSetOrientationHint(mNativeObject, degrees);
} else {
throw new IllegalStateException("Can't set rotation degrees due" +
- " to wrong state.");
+ " to wrong state(" + convertMuxerStateCodeToString(mState) + ")");
}
}
@@ -432,7 +447,8 @@
if (mState == MUXER_STATE_INITIALIZED && mNativeObject != 0) {
nativeSetLocation(mNativeObject, latitudex10000, longitudex10000);
} else {
- throw new IllegalStateException("Can't set location due to wrong state.");
+ throw new IllegalStateException("Can't set location due to wrong state("
+ + convertMuxerStateCodeToString(mState) + ")");
}
}
@@ -451,7 +467,8 @@
nativeStart(mNativeObject);
mState = MUXER_STATE_STARTED;
} else {
- throw new IllegalStateException("Can't start due to wrong state.");
+ throw new IllegalStateException("Can't start due to wrong state("
+ + convertMuxerStateCodeToString(mState) + ")");
}
}
@@ -462,10 +479,16 @@
*/
public void stop() {
if (mState == MUXER_STATE_STARTED) {
- nativeStop(mNativeObject);
- mState = MUXER_STATE_STOPPED;
+ try {
+ nativeStop(mNativeObject);
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ mState = MUXER_STATE_STOPPED;
+ }
} else {
- throw new IllegalStateException("Can't stop due to wrong state.");
+ throw new IllegalStateException("Can't stop due to wrong state("
+ + convertMuxerStateCodeToString(mState) + ")");
}
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 7d14ef5..6179b48 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -98,7 +98,7 @@
final Handler mHandler;
@GuardedBy("sRouterLock")
- private boolean mShouldUpdateRoutes;
+ private boolean mShouldUpdateRoutes = true;
private volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
private volatile OnGetControllerHintsListener mOnGetControllerHintsListener;
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 5d61dd0..4ebfce8 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -101,6 +100,7 @@
.getSystemService(Context.MEDIA_SESSION_SERVICE);
mPackageName = mContext.getPackageName();
mHandler = new Handler(context.getMainLooper());
+ mHandler.post(this::getOrCreateClient);
}
/**
@@ -119,18 +119,6 @@
Log.w(TAG, "Ignoring to add the same callback twice.");
return;
}
-
- synchronized (sLock) {
- if (mClient == null) {
- Client client = new Client();
- try {
- mMediaRouterService.registerManager(client, mPackageName);
- mClient = client;
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to register media router manager.", ex);
- }
- }
- }
}
/**
@@ -145,21 +133,6 @@
Log.w(TAG, "unregisterCallback: Ignore unknown callback. " + callback);
return;
}
-
- synchronized (sLock) {
- if (mCallbackRecords.size() == 0) {
- if (mClient != null) {
- try {
- mMediaRouterService.unregisterManager(mClient);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to unregister media router manager", ex);
- }
- mClient = null;
- }
- mRoutes.clear();
- mPreferredFeaturesMap.clear();
- }
- }
}
/**
@@ -171,8 +144,7 @@
public MediaController getMediaControllerForRoutingSession(
@NonNull RoutingSessionInfo sessionInfo) {
for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
- String volumeControlId = controller.getPlaybackInfo().getVolumeControlId();
- if (TextUtils.equals(sessionInfo.getId(), volumeControlId)) {
+ if (areSessionsMatched(controller, sessionInfo)) {
return controller;
}
}
@@ -207,6 +179,37 @@
}
/**
+ * Gets available routes for the given routing session.
+ * The returned routes can be passed to
+ * {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} for transferring the routing session.
+ *
+ * @param sessionInfo the routing session that would be transferred
+ */
+ @NonNull
+ public List<MediaRoute2Info> getAvailableRoutesForRoutingSession(
+ @NonNull RoutingSessionInfo sessionInfo) {
+ Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+
+ List<MediaRoute2Info> routes = new ArrayList<>();
+
+ String packageName = sessionInfo.getClientPackageName();
+ List<String> preferredFeatures = mPreferredFeaturesMap.get(packageName);
+ if (preferredFeatures == null) {
+ preferredFeatures = Collections.emptyList();
+ }
+ synchronized (mRoutesLock) {
+ for (MediaRoute2Info route : mRoutes.values()) {
+ if (route.isSystemRoute() || route.hasAnyFeatures(preferredFeatures)
+ || sessionInfo.getSelectedRoutes().contains(route.getId())
+ || sessionInfo.getTransferableRoutes().contains(route.getId())) {
+ routes.add(route);
+ }
+ }
+ }
+ return routes;
+ }
+
+ /**
* Gets the system routing session associated with no specific application.
*/
@NonNull
@@ -220,6 +223,33 @@
}
/**
+ * Gets the routing session of a media session.
+ * If the session is using {#link PlaybackInfo#PLAYBACK_TYPE_LOCAL local playback},
+ * the system routing session is returned.
+ * If the session is using {#link PlaybackInfo#PLAYBACK_TYPE_REMOTE remote playback},
+ * it returns the corresponding routing session or {@code null} if it's unavailable.
+ */
+ @Nullable
+ public RoutingSessionInfo getRoutingSessionForMediaController(MediaController mediaController) {
+ MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo();
+ if (playbackInfo == null) {
+ return null;
+ }
+ if (playbackInfo.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ return new RoutingSessionInfo.Builder(getSystemRoutingSession())
+ .setClientPackageName(mediaController.getPackageName())
+ .build();
+ }
+ for (RoutingSessionInfo sessionInfo : getActiveSessions()) {
+ if (!sessionInfo.isSystemSession()
+ && areSessionsMatched(mediaController, sessionInfo)) {
+ return sessionInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
* Gets routing sessions of an application with the given package name.
* The first element of the returned list is the system routing session.
*
@@ -258,10 +288,7 @@
*/
@NonNull
public List<RoutingSessionInfo> getActiveSessions() {
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
return mMediaRouterService.getActiveSessions(client);
@@ -324,10 +351,7 @@
return;
}
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
@@ -344,14 +368,6 @@
/**
* Requests a volume change for a route asynchronously.
- */
- //TODO: remove this.
- public void requestSetVolume(MediaRoute2Info route, int volume) {
- setRouteVolume(route, volume);
- }
-
- /**
- * Requests a volume change for a route asynchronously.
* <p>
* It may have no effect if the route is currently not selected.
* </p>
@@ -371,10 +387,7 @@
return;
}
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
@@ -403,10 +416,7 @@
return;
}
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
@@ -576,30 +586,22 @@
}
for (CallbackRecord record : mCallbackRecords) {
record.mExecutor.execute(() -> record.mCallback
- .onControlCategoriesChanged(packageName, preferredFeatures));
- }
- for (CallbackRecord record : mCallbackRecords) {
- record.mExecutor.execute(() -> record.mCallback
.onPreferredFeaturesChanged(packageName, preferredFeatures));
}
}
/**
- * @hide
- */
- public RoutingController getControllerForSession(@NonNull RoutingSessionInfo sessionInfo) {
- return new RoutingController(sessionInfo);
- }
-
- /**
* Gets the unmodifiable list of selected routes for the session.
*/
@NonNull
public List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- List<String> routeIds = sessionInfo.getSelectedRoutes();
- return getRoutesWithIds(routeIds);
+ synchronized (sLock) {
+ return sessionInfo.getSelectedRoutes().stream().map(mRoutes::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
/**
@@ -609,8 +611,15 @@
public List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- List<String> routeIds = sessionInfo.getSelectableRoutes();
- return getRoutesWithIds(routeIds);
+ List<String> selectedRouteIds = sessionInfo.getSelectedRoutes();
+
+ synchronized (sLock) {
+ return sessionInfo.getSelectableRoutes().stream()
+ .filter(routeId -> !selectedRouteIds.contains(routeId))
+ .map(mRoutes::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
/**
@@ -620,8 +629,15 @@
public List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- List<String> routeIds = sessionInfo.getDeselectableRoutes();
- return getRoutesWithIds(routeIds);
+ List<String> selectedRouteIds = sessionInfo.getSelectedRoutes();
+
+ synchronized (sLock) {
+ return sessionInfo.getDeselectableRoutes().stream()
+ .filter(routeId -> selectedRouteIds.contains(routeId))
+ .map(mRoutes::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
/**
@@ -656,15 +672,12 @@
return;
}
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.selectRouteWithManager(
- mClient, requestId, sessionInfo.getId(), route);
+ client, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "selectRoute: Failed to send a request.", ex);
}
@@ -701,15 +714,12 @@
return;
}
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.deselectRouteWithManager(
- mClient, requestId, sessionInfo.getId(), route);
+ client, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "deselectRoute: Failed to send a request.", ex);
}
@@ -740,14 +750,11 @@
int requestId = mNextRequestId.getAndIncrement();
mTransferRequests.add(new TransferRequest(requestId, sessionInfo, route));
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
mMediaRouterService.transferToRouteWithManager(
- mClient, requestId, sessionInfo.getId(), route);
+ client, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "transferToRoute: Failed to send a request.", ex);
}
@@ -767,169 +774,54 @@
public void releaseSession(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
+ Client client = getOrCreateClient();
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.releaseSessionWithManager(
- mClient, requestId, sessionInfo.getId());
+ client, requestId, sessionInfo.getId());
} catch (RemoteException ex) {
Log.e(TAG, "releaseSession: Failed to send a request", ex);
}
}
}
- private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) {
- synchronized (sLock) {
- return routeIds.stream().map(mRoutes::get)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
+ private boolean areSessionsMatched(MediaController mediaController,
+ RoutingSessionInfo sessionInfo) {
+ MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo();
+ if (playbackInfo == null) {
+ return false;
}
+
+ String volumeControlId = playbackInfo.getVolumeControlId();
+ if (volumeControlId == null) {
+ return false;
+ }
+
+ if (TextUtils.equals(volumeControlId, sessionInfo.getId())) {
+ return true;
+ }
+ // Workaround for provider not being able to know the unique session ID.
+ return TextUtils.equals(volumeControlId, sessionInfo.getOriginalId())
+ && TextUtils.equals(mediaController.getPackageName(),
+ sessionInfo.getOwnerPackageName());
}
- //TODO: Remove this.
- /**
- * A class to control media routing session in media route provider.
- * With routing controller, an application can select a route into the session or deselect
- * a route in the session.
- */
- public final class RoutingController {
- private final Object mControllerLock = new Object();
- @GuardedBy("mControllerLock")
- private RoutingSessionInfo mSessionInfo;
-
- RoutingController(@NonNull RoutingSessionInfo sessionInfo) {
- mSessionInfo = sessionInfo;
- }
-
- /**
- * Releases the session
- */
- public void release() {
- synchronized (mControllerLock) {
- releaseSession(mSessionInfo);
+ private Client getOrCreateClient() {
+ synchronized (sLock) {
+ if (mClient != null) {
+ return mClient;
+ }
+ Client client = new Client();
+ try {
+ mMediaRouterService.registerManager(client, mPackageName);
+ mClient = client;
+ return client;
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to register media router manager.", ex);
}
}
-
- /**
- * Gets the ID of the session
- */
- @NonNull
- public String getSessionId() {
- synchronized (mControllerLock) {
- return mSessionInfo.getId();
- }
- }
-
- /**
- * Gets the client package name of the session
- */
- @NonNull
- public String getClientPackageName() {
- synchronized (mControllerLock) {
- return mSessionInfo.getClientPackageName();
- }
- }
-
- /**
- * @return the control hints used to control route session if available.
- */
- @Nullable
- public Bundle getControlHints() {
- synchronized (mControllerLock) {
- return mSessionInfo.getControlHints();
- }
- }
-
- /**
- * @return the unmodifiable list of currently selected routes
- */
- @NonNull
- public List<MediaRoute2Info> getSelectedRoutes() {
- return MediaRouter2Manager.this.getSelectedRoutes(mSessionInfo);
- }
-
- /**
- * @return the unmodifiable list of selectable routes for the session.
- */
- @NonNull
- public List<MediaRoute2Info> getSelectableRoutes() {
- return MediaRouter2Manager.this.getSelectableRoutes(mSessionInfo);
- }
-
- /**
- * @return the unmodifiable list of deselectable routes for the session.
- */
- @NonNull
- public List<MediaRoute2Info> getDeselectableRoutes() {
- return MediaRouter2Manager.this.getDeselectableRoutes(mSessionInfo);
- }
-
- /**
- * @return the unmodifiable list of transferable routes for the session.
- */
- @NonNull
- public List<MediaRoute2Info> getTransferableRoutes() {
- List<String> routeIds;
- synchronized (mControllerLock) {
- routeIds = mSessionInfo.getTransferableRoutes();
- }
- return getRoutesWithIds(routeIds);
- }
-
- /**
- * Selects a route for the remote session. The given route must satisfy all of the
- * following conditions:
- * <ul>
- * <li>ID should not be included in {@link #getSelectedRoutes()}</li>
- * <li>ID should be included in {@link #getSelectableRoutes()}</li>
- * </ul>
- * If the route doesn't meet any of above conditions, it will be ignored.
- *
- * @see #getSelectedRoutes()
- * @see #getSelectableRoutes()
- */
- public void selectRoute(@NonNull MediaRoute2Info route) {
- MediaRouter2Manager.this.selectRoute(mSessionInfo, route);
- }
-
- /**
- * Deselects a route from the remote session. The given route must satisfy all of the
- * following conditions:
- * <ul>
- * <li>ID should be included in {@link #getSelectedRoutes()}</li>
- * <li>ID should be included in {@link #getDeselectableRoutes()}</li>
- * </ul>
- * If the route doesn't meet any of above conditions, it will be ignored.
- *
- * @see #getSelectedRoutes()
- * @see #getDeselectableRoutes()
- */
- public void deselectRoute(@NonNull MediaRoute2Info route) {
- MediaRouter2Manager.this.deselectRoute(mSessionInfo, route);
- }
-
- /**
- * Transfers session to the given rotue.
- */
- public void transferToRoute(@NonNull MediaRoute2Info route) {
- MediaRouter2Manager.this.transferToRoute(mSessionInfo, route);
- }
-
- /**
- * Gets the session info of the session
- *
- * @hide
- */
- @NonNull
- public RoutingSessionInfo getSessionInfo() {
- synchronized (mControllerLock) {
- return mSessionInfo;
- }
- }
+ return null;
}
/**
@@ -976,16 +868,6 @@
public void onTransferFailed(@NonNull RoutingSessionInfo session,
@NonNull MediaRoute2Info route) { }
- //TODO: Remove this.
- /**
- * Called when the preferred route features of an app is changed.
- *
- * @param packageName the package name of the application
- * @param preferredFeatures the list of preferred route features set by an application.
- */
- public void onControlCategoriesChanged(@NonNull String packageName,
- @NonNull List<String> preferredFeatures) {}
-
/**
* Called when the preferred route features of an app is changed.
*
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 608e29a..edf1fc5 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -50,6 +50,7 @@
final String mId;
final CharSequence mName;
+ final String mOwnerPackageName;
final String mClientPackageName;
@Nullable
final String mProviderId;
@@ -71,6 +72,7 @@
mId = builder.mId;
mName = builder.mName;
+ mOwnerPackageName = builder.mOwnerPackageName;
mClientPackageName = builder.mClientPackageName;
mProviderId = builder.mProviderId;
@@ -96,6 +98,7 @@
mId = ensureString(src.readString());
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+ mOwnerPackageName = src.readString();
mClientPackageName = ensureString(src.readString());
mProviderId = src.readString();
@@ -159,6 +162,15 @@
}
/**
+ * Gets the package name of the session owner.
+ * @hide
+ */
+ @Nullable
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
+ /**
* Gets the client package name of the session
*/
@NonNull
@@ -263,6 +275,7 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mId);
dest.writeCharSequence(mName);
+ dest.writeString(mOwnerPackageName);
dest.writeString(mClientPackageName);
dest.writeString(mProviderId);
dest.writeStringList(mSelectedRoutes);
@@ -288,6 +301,7 @@
RoutingSessionInfo other = (RoutingSessionInfo) obj;
return Objects.equals(mId, other.mId)
&& Objects.equals(mName, other.mName)
+ && Objects.equals(mOwnerPackageName, other.mOwnerPackageName)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
&& Objects.equals(mProviderId, other.mProviderId)
&& Objects.equals(mSelectedRoutes, other.mSelectedRoutes)
@@ -301,7 +315,7 @@
@Override
public int hashCode() {
- return Objects.hash(mId, mName, mClientPackageName, mProviderId,
+ return Objects.hash(mId, mName, mOwnerPackageName, mClientPackageName, mProviderId,
mSelectedRoutes, mSelectableRoutes, mDeselectableRoutes, mTransferableRoutes,
mVolumeMax, mVolumeHandling, mVolume);
}
@@ -356,6 +370,7 @@
// TODO: Reorder these (important ones first)
final String mId;
CharSequence mName;
+ String mOwnerPackageName;
String mClientPackageName;
String mProviderId;
final List<String> mSelectedRoutes;
@@ -440,6 +455,17 @@
}
/**
+ * Sets the package name of the session owner. It is expected to be called by the system.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setOwnerPackageName(@Nullable String packageName) {
+ mOwnerPackageName = packageName;
+ return this;
+ }
+
+ /**
* Sets the client package name of the session.
*
* @hide
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index b5e2213..c4d27ec 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -23,8 +23,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.media.projection.IMediaProjection;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -86,6 +84,12 @@
* capture request. Will be null if the result from the
* startActivityForResult() is anything other than RESULT_OK.
*
+ * Starting from Android {@link android.os.Build.VERSION_CODES#R}, if your application requests
+ * the {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW} permission, and the
+ * user has not explicitly denied it, the permission will be automatically granted until the
+ * projection is stopped. This allows for user controls to be displayed on top of the screen
+ * being captured.
+ *
* @param resultCode The result code from {@link android.app.Activity#onActivityResult(int,
* int, android.content.Intent)}
* @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int,
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f058a02..e701055 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1805,7 +1805,7 @@
String tvInputSessionId, int priorityHint,
Executor executor, final HardwareCallback callback) {
try {
- return new Hardware(
+ ITvInputHardware hardware =
mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@Override
public void onReleased() {
@@ -1826,7 +1826,11 @@
Binder.restoreCallingIdentity(identity);
}
}
- }, info, mUserId, tvInputSessionId, priorityHint));
+ }, info, mUserId, tvInputSessionId, priorityHint);
+ if (hardware == null) {
+ return null;
+ }
+ return new Hardware(hardware);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
index 598ff8f..28f1ac9 100644
--- a/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
+++ b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
@@ -17,6 +17,7 @@
package android.media.tv.tunerresourcemanager;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -81,7 +82,7 @@
* OEM. The id of the useCaseVendor should be passed through this parameter. Any
* undefined use case would cause IllegalArgumentException.
*/
- public ResourceClientProfile(@NonNull String tvInputSessionId,
+ public ResourceClientProfile(@Nullable String tvInputSessionId,
int useCase) {
mTvInputSessionId = tvInputSessionId;
mUseCase = useCase;
@@ -92,7 +93,7 @@
*
* @return the value of the tv input session id.
*/
- @NonNull
+ @Nullable
public String getTvInputSessionId() {
return mTvInputSessionId;
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 98e68b8..43cb25f 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -43,7 +43,7 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
-#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryDealer.h>
#include <cutils/compiler.h>
@@ -306,6 +306,7 @@
CHECK(format->findString("mime", &mime));
mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
&& !(flags & CONFIGURE_FLAG_ENCODE);
+ mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
return mCodec->configure(
format, mSurfaceTextureClient, crypto, descrambler, flags);
@@ -1233,7 +1234,7 @@
jboolean enabled) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1249,7 +1250,7 @@
jobject cb) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1269,7 +1270,7 @@
jint flags) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1317,7 +1318,7 @@
jobject jsurface) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1440,7 +1441,7 @@
ALOGV("android_media_MediaCodec_setInputSurface");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1464,7 +1465,7 @@
ALOGV("android_media_MediaCodec_createInputSurface");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1487,7 +1488,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1502,7 +1503,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1517,7 +1518,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1539,7 +1540,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1561,7 +1562,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1603,14 +1604,13 @@
ScopedLocalRef<jobject> patternObj{
env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
- CryptoPlugin::Pattern pattern;
if (patternObj.get() == nullptr) {
- pattern.mEncryptBlocks = 0;
- pattern.mSkipBlocks = 0;
+ mPattern.mEncryptBlocks = 0;
+ mPattern.mSkipBlocks = 0;
} else {
- pattern.mEncryptBlocks = env->GetIntField(
+ mPattern.mEncryptBlocks = env->GetIntField(
patternObj.get(), gFields.patternEncryptBlocksID);
- pattern.mSkipBlocks = env->GetIntField(
+ mPattern.mSkipBlocks = env->GetIntField(
patternObj.get(), gFields.patternSkipBlocksID);
}
@@ -1679,6 +1679,18 @@
mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
}
}
+
+ }
+
+ explicit NativeCryptoInfo(jint size)
+ : mIvObj{nullptr, nullptr},
+ mKeyObj{nullptr, nullptr},
+ mMode{CryptoPlugin::kMode_Unencrypted},
+ mPattern{0, 0} {
+ mSubSamples = new CryptoPlugin::SubSample[1];
+ mNumSubSamples = 1;
+ mSubSamples[0].mNumBytesOfClearData = size;
+ mSubSamples[0].mNumBytesOfEncryptedData = 0;
}
~NativeCryptoInfo() {
@@ -1720,7 +1732,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2109,7 +2121,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == nullptr) {
+ if (codec == nullptr || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2128,10 +2140,13 @@
if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
JMediaCodecLinearBlock *context =
(JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
- if (cryptoInfoObj != nullptr) {
+ if (codec->hasCryptoOrDescrambler()) {
memory = context->toHidlMemory();
+ // TODO: copy if memory is null
+ offset += context->mHidlMemoryOffset;
} else {
buffer = context->toC2Buffer(offset, size);
+ // TODO: copy if buffer is null
}
}
env->MonitorExit(lock.get());
@@ -2141,13 +2156,19 @@
}
AString errorDetailMsg;
- if (cryptoInfoObj != nullptr) {
+ if (codec->hasCryptoOrDescrambler()) {
if (!memory) {
+ ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
throwExceptionAsNecessary(env, BAD_VALUE);
return;
}
-
- NativeCryptoInfo cryptoInfo{env, cryptoInfoObj};
+ NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
+ if (cryptoInfoObj == nullptr) {
+ return NativeCryptoInfo{size};
+ } else {
+ return NativeCryptoInfo{env, cryptoInfoObj};
+ }
+ }();
err = codec->queueEncryptedLinearBlock(
index,
memory,
@@ -2162,6 +2183,7 @@
&errorDetailMsg);
} else {
if (!buffer) {
+ ALOGI("queueLinearBlock: no C2Buffer found");
throwExceptionAsNecessary(env, BAD_VALUE);
return;
}
@@ -2178,7 +2200,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2227,7 +2249,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2244,7 +2266,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return -1;
}
@@ -2265,7 +2287,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return 0;
}
@@ -2288,7 +2310,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2303,7 +2325,7 @@
ALOGV("android_media_MediaCodec_signalEndOfInputStream");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2319,7 +2341,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2342,7 +2364,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2365,7 +2387,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2391,7 +2413,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2417,7 +2439,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2443,7 +2465,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2466,7 +2488,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -2489,7 +2511,7 @@
ALOGV("android_media_MediaCodec_native_getMetrics");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL ) {
+ if (codec == NULL || codec->initCheck() != OK) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return 0;
}
@@ -2518,7 +2540,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2537,7 +2559,7 @@
JNIEnv *env, jobject thiz, jint mode) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2555,7 +2577,7 @@
JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec == NULL) {
+ if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -2955,13 +2977,13 @@
context->mLegacyBuffer->size(),
true, // readOnly
true /* clearBuffer */);
- } else if (context->mHeap) {
+ } else if (context->mMemory) {
return CreateByteBuffer(
env,
- static_cast<uint8_t *>(context->mHeap->getBase()) + context->mHeap->getOffset(),
- context->mHeap->getSize(),
+ context->mMemory->unsecurePointer(),
+ context->mMemory->size(),
0,
- context->mHeap->getSize(),
+ context->mMemory->size(),
false, // readOnly
true /* clearBuffer */);
}
@@ -3011,8 +3033,26 @@
}
}
if (hasSecure && !hasNonSecure) {
- context->mHeap = new MemoryHeapBase(capacity);
- context->mMemory = hardware::fromHeap(context->mHeap);
+ constexpr size_t kInitialDealerCapacity = 1048576; // 1MB
+ thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
+ kInitialDealerCapacity, "JNI(1MB)");
+ context->mMemory = sDealer->allocate(capacity);
+ if (context->mMemory == nullptr) {
+ size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
+ while (capacity * 2 > newDealerCapacity) {
+ newDealerCapacity *= 2;
+ }
+ ALOGI("LinearBlock.native_obtain: "
+ "Dealer capacity increasing from %zuMB to %zuMB",
+ sDealer->getMemoryHeap()->getSize() / 1048576,
+ newDealerCapacity / 1048576);
+ sDealer = new MemoryDealer(
+ newDealerCapacity,
+ AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
+ context->mMemory = sDealer->allocate(capacity);
+ }
+ context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
+ &context->mHidlMemoryOffset, &context->mHidlMemorySize));
} else {
context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
if (!context->mBlock) {
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 400ce1b..5c34341 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -162,6 +162,8 @@
void selectAudioPresentation(const int32_t presentationId, const int32_t programId);
+ bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
+
protected:
virtual ~JMediaCodec();
@@ -181,6 +183,7 @@
sp<MediaCodec> mCodec;
AString mNameAtCreation;
bool mGraphicOutput{false};
+ bool mHasCryptoOrDescrambler{false};
std::once_flag mReleaseFlag;
sp<AMessage> mCallbackNotification;
diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h
index 0843834..8f1d2fa 100644
--- a/media/jni/android_media_MediaCodecLinearBlock.h
+++ b/media/jni/android_media_MediaCodecLinearBlock.h
@@ -31,8 +31,10 @@
std::shared_ptr<C2LinearBlock> mBlock;
std::shared_ptr<C2WriteView> mReadWriteMapping;
- sp<IMemoryHeap> mHeap;
- sp<hardware::HidlMemory> mMemory;
+ sp<IMemory> mMemory;
+ sp<hardware::HidlMemory> mHidlMemory;
+ ssize_t mHidlMemoryOffset;
+ size_t mHidlMemorySize;
sp<MediaCodecBuffer> mLegacyBuffer;
@@ -56,8 +58,8 @@
}
sp<hardware::HidlMemory> toHidlMemory() {
- if (mMemory) {
- return mMemory;
+ if (mHidlMemory) {
+ return mHidlMemory;
}
return nullptr;
}
@@ -65,4 +67,4 @@
} // namespace android
-#endif // _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_
\ No newline at end of file
+#endif // _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 0c1e9a2..262ec76 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -26,15 +26,11 @@
#include <unistd.h>
#include <fcntl.h>
-#include <android/api-level.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaMuxer.h>
-extern "C" int android_get_application_target_sdk_version();
-
namespace android {
struct fields_t {
@@ -233,31 +229,11 @@
status_t err = muxer->stop();
- if (android_get_application_target_sdk_version() >= __ANDROID_API_R__) {
- switch (err) {
- case OK:
- break;
- case ERROR_IO: {
- jniThrowException(env, "java/lang/UncheckedIOException",
- "Muxer stopped unexpectedly");
- return;
- }
- case ERROR_MALFORMED: {
- jniThrowException(env, "java/io/IOError",
- "Failure of reading or writing operation");
- return;
- }
- default: {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to stop the muxer");
- return;
- }
- }
- } else {
- if (err != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to stop the muxer");
- return;
- }
+ if (err != OK) {
+ ALOGE("Error during stop:%d", err);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Error during stop(), muxer would have stopped already");
+ return;
}
}
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 daeb731..0ae640d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -58,6 +58,7 @@
import android.util.Log;
import android.util.Pair;
import android.util.Size;
+import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
@@ -2210,14 +2211,14 @@
}
public static Size getPreviewSizeBound(WindowManager windowManager, Size bound) {
- Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
+ Display display = windowManager.getDefaultDisplay();
- int width = windowBounds.width();
- int height = windowBounds.height();
+ int width = display.getWidth();
+ int height = display.getHeight();
if (height > width) {
height = width;
- width = windowBounds.height();
+ width = display.getHeight();
}
if (bound.getWidth() <= width &&
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 6a1e965..c05c21c 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -26,6 +26,7 @@
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID1;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID2;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
@@ -68,6 +69,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -566,6 +568,46 @@
assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
}
+ /**
+ * Tests if getSelectableRoutes and getDeselectableRoutes filter routes based on
+ * selected routes
+ */
+ @Test
+ public void testGetSelectableRoutes_notReturnsSelectedRoutes() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ addRouterCallback(new RouteCallback() {});
+
+ CountDownLatch onSessionCreatedLatch = new CountDownLatch(1);
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ assertNotNull(newSessionInfo);
+ List<String> selectedRoutes = mManager.getSelectedRoutes(newSessionInfo).stream()
+ .map(MediaRoute2Info::getId)
+ .collect(Collectors.toList());
+ for (MediaRoute2Info selectableRoute :
+ mManager.getSelectableRoutes(newSessionInfo)) {
+ assertFalse(selectedRoutes.contains(selectableRoute.getId()));
+ }
+ for (MediaRoute2Info deselectableRoute :
+ mManager.getDeselectableRoutes(newSessionInfo)) {
+ assertTrue(selectedRoutes.contains(deselectableRoute.getId()));
+ }
+ onSessionCreatedLatch.countDown();
+ }
+ });
+
+ mManager.selectRoute(mPackageName, routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT));
+ assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testGetActiveSessions_returnsNonEmptyList() {
+ assertFalse(mManager.getActiveSessions().isEmpty());
+ }
+
Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
throws Exception {
CountDownLatch addedLatch = new CountDownLatch(1);
diff --git a/native/android/Android.bp b/native/android/Android.bp
index ed73f39..797d3fd 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -37,6 +37,7 @@
srcs: [
"asset_manager.cpp",
+ "choreographer.cpp",
"configuration.cpp",
"hardware_buffer_jni.cpp",
"input.cpp",
@@ -49,6 +50,7 @@
"sharedmem.cpp",
"storage_manager.cpp",
"surface_control.cpp",
+ "surface_texture.cpp",
"system_fonts.cpp",
"trace.cpp",
"thermal.cpp"
@@ -76,6 +78,7 @@
"libpowermanager",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
+ "libnativedisplay",
],
static_libs: [
@@ -83,9 +86,9 @@
"libarect",
],
- header_libs: [ "libhwui_internal_headers" ],
+ header_libs: [ "libhwui_internal_headers",],
- whole_static_libs: ["libnativedisplay", "libnativewindow"],
+ whole_static_libs: ["libnativewindow"],
export_static_lib_headers: ["libarect"],
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
new file mode 100644
index 0000000..38641de
--- /dev/null
+++ b/native/android/choreographer.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <private/android/choreographer.h>
+
+using namespace android;
+
+AChoreographer* AChoreographer_getInstance() {
+ return AChoreographer_routeGetInstance();
+}
+void AChoreographer_postFrameCallback(AChoreographer* choreographer,
+ AChoreographer_frameCallback callback, void* data) {
+ return AChoreographer_routePostFrameCallback(choreographer, callback, data);
+}
+void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
+ AChoreographer_frameCallback callback, void* data,
+ long delayMillis) {
+ return AChoreographer_routePostFrameCallbackDelayed(choreographer, callback, data, delayMillis);
+}
+void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback, void* data) {
+ return AChoreographer_routePostFrameCallback64(choreographer, callback, data);
+}
+void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback, void* data,
+ uint32_t delayMillis) {
+ return AChoreographer_routePostFrameCallbackDelayed64(choreographer, callback, data,
+ delayMillis);
+}
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ return AChoreographer_routeRegisterRefreshRateCallback(choreographer, callback, data);
+}
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ return AChoreographer_routeUnregisterRefreshRateCallback(choreographer, callback, data);
+}
diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp
new file mode 100644
index 0000000..ff35204
--- /dev/null
+++ b/native/android/surface_texture.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/surface_texture_jni.h>
+#include <surfacetexture/surface_texture_platform.h>
+
+using namespace android;
+
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
+ return ASurfaceTexture_routeAcquireANativeWindow(st);
+}
+
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) {
+ return ASurfaceTexture_routeAttachToGLContext(st, texName);
+}
+
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) {
+ return ASurfaceTexture_routeDetachFromGLContext(st);
+}
+
+void ASurfaceTexture_release(ASurfaceTexture* st) {
+ return ASurfaceTexture_routeRelease(st);
+}
+
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) {
+ return ASurfaceTexture_routeUpdateTexImage(st);
+}
+
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+ return ASurfaceTexture_routeGetTransformMatrix(st, mtx);
+}
+
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) {
+ return ASurfaceTexture_routeGetTimestamp(st);
+}
+
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+ return ASurfaceTexture_routeFromSurfaceTexture(env, surfacetexture);
+}
diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml
index 261b9f5..1dd0291 100644
--- a/packages/CarSystemUI/AndroidManifest.xml
+++ b/packages/CarSystemUI/AndroidManifest.xml
@@ -25,4 +25,6 @@
<uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/>
<!-- This permission is required to get bluetooth broadcast. -->
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <!-- This permission is required to check the foreground user id. -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
</manifest>
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 3389a7a..60e0d7e 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -76,7 +76,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
- systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivity;launchFlags=0x24000000;end"
+ systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end"
/>
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
diff --git a/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml b/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml
new file mode 100644
index 0000000..0a29424
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fitsSystemWindows="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:background="@color/car_user_switching_dialog_background_color">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="center"
+ android:gravity="center_horizontal">
+ <ImageView
+ android:id="@+id/user_loading_avatar"
+ android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
+ android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"/>
+
+ <TextView
+ android:id="@+id/user_loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/car_user_switching_dialog_loading_text_margin_top"
+ android:textSize="@dimen/car_user_switching_dialog_loading_text_font_size"
+ android:textColor="@color/car_user_switching_dialog_loading_text_color"
+ android:layout_below="@id/user_loading_avatar"/>
+ </LinearLayout>
+</FrameLayout>
diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
index 3542323..2dc499c 100644
--- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
@@ -39,4 +39,9 @@
android:layout_height="match_parent"
android:layout="@layout/car_fullscreen_user_switcher"/>
+ <ViewStub android:id="@+id/user_switching_dialog_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/car_user_switching_dialog"/>
+
</FrameLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index 3e44721..0e84d51 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -55,4 +55,7 @@
<color name="list_divider_color">@*android:color/car_list_divider_light</color>
<color name="car_volume_item_divider_color">@*android:color/car_list_divider</color>
<color name="car_volume_item_background_color">@*android:color/car_card_dark</color>
+
+ <color name="car_user_switching_dialog_background_color">@android:color/black</color>
+ <color name="car_user_switching_dialog_loading_text_color">@*android:color/car_body1</color>
</resources>
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 67066d7..4bf0fca 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -70,11 +70,13 @@
to a constant alpha percent value using the initial alpha. -->
<integer name="config_finalNotificationBackgroundAlpha">100</integer>
- <!-- Car System UI's OverlayViewsMediator-->
+ <!-- Car System UI's OverlayViewsMediator.
+ Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
<string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
<item>@string/config_notificationPanelViewMediator</item>
<item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
<item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
+ <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
</string-array>
<!--
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 9014eb1..ed0b485 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -15,6 +15,32 @@
~ limitations under the License
-->
<resources>
+ <!-- Text size for car -->
+ <dimen name="car_title_size">32sp</dimen>
+ <dimen name="car_title2_size">32sp</dimen>
+ <dimen name="car_headline1_size">45sp</dimen>
+ <dimen name="car_headline2_size">32sp</dimen>
+ <dimen name="car_headline3_size">24sp</dimen>
+ <dimen name="car_headline4_size">20sp</dimen>
+ <dimen name="car_body1_size">32sp</dimen>
+ <dimen name="car_body2_size">28sp</dimen>
+ <dimen name="car_body3_size">26sp</dimen>
+ <dimen name="car_body4_size">24sp</dimen>
+ <!-- car_body5_size is deprecated -->
+ <dimen name="car_body5_size">18sp</dimen>
+ <dimen name="car_label1_size">26sp</dimen>
+ <dimen name="car_label2_size">64sp</dimen>
+ <dimen name="car_action1_size">26sp</dimen>
+ <dimen name="car_action2_size">26sp</dimen>
+ <!-- Paddings -->
+ <dimen name="car_padding_0">4dp</dimen>
+ <dimen name="car_padding_1">8dp</dimen>
+ <dimen name="car_padding_2">16dp</dimen>
+ <dimen name="car_padding_3">24dp</dimen>
+ <dimen name="car_padding_4">32dp</dimen>
+ <dimen name="car_padding_5">64dp</dimen>
+ <dimen name="car_padding_6">96dp</dimen>
+
<!--
Note: status bar height and navigation bar heights are defined
in frameworks/base/core package and thus will have no effect if
@@ -156,4 +182,10 @@
<dimen name="car_user_switcher_container_height">420dp</dimen>
<!-- This must be the negative of car_user_switcher_container_height for the animation. -->
<dimen name="car_user_switcher_container_anim_height">-420dp</dimen>
+
+ <!-- dimensions for car user switching dialog -->
+ <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
+ <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
+ <dimen name="car_user_switching_dialog_loading_text_margin_top">@*android:dimen/car_padding_4</dimen>
+ <dimen name="car_user_switching_dialog_loading_text_font_size">@*android:dimen/car_body1_size</dimen>
</resources>
diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml
index 9fae4b3..67fd5bb 100644
--- a/packages/CarSystemUI/res/values/strings.xml
+++ b/packages/CarSystemUI/res/values/strings.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- String to represent lowest setting of an HVAC system [CHAR LIMIT=10]-->
<string name="hvac_min_text">Min</string>
<!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->
@@ -34,4 +34,8 @@
<string name="user_add_user_message_setup">When you add a new user, that person needs to set up their space.</string>
<!-- Message to inform user that the newly created user will have permissions to update apps for all other users. [CHAR LIMIT=100] -->
<string name="user_add_user_message_update">Any user can update apps for all other users.</string>
+ <!-- Message to inform user that the new user profile is loading. [CHAR LIMIT=20] -->
+ <string name="car_loading_profile">Loading</string>
+ <!-- Message to inform user that the new user profile is loading with additional information on the previous and the next user. [CHAR LIMIT=100] -->
+ <string name="car_loading_profile_developer_message">Loading user (from <xliff:g id="from_user" example="10">%1$d</xliff:g> to <xliff:g id="to_user" example="12">%2$d</xliff:g>)</string>
</resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index ab7bf5e..fe2be1d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -20,18 +20,25 @@
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
import com.android.keyguard.KeyguardViewController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
import com.android.systemui.car.keyguard.CarKeyguardViewController;
import com.android.systemui.car.statusbar.CarStatusBar;
import com.android.systemui.car.statusbar.CarStatusBarKeyguardViewManager;
+import com.android.systemui.car.statusbar.DozeServiceHost;
import com.android.systemui.car.statusbar.DummyNotificationShadeWindowController;
import com.android.systemui.car.volume.CarVolumeDialogComponent;
import com.android.systemui.dagger.SystemUIRootComponent;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
+import com.android.systemui.doze.DozeHost;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
@@ -113,10 +120,17 @@
abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager(
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
- @Binds
+ @Provides
@Singleton
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
+ static BatteryController provideBatteryController(Context context,
+ EnhancedEstimates enhancedEstimates, PowerManager powerManager,
+ BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler,
+ @Background Handler bgHandler) {
+ BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
+ broadcastDispatcher, mainHandler, bgHandler);
+ bC.init();
+ return bC;
+ }
@Binds
@Singleton
@@ -162,4 +176,7 @@
@Binds
abstract NotificationShadeWindowController bindNotificationShadeWindowController(
DummyNotificationShadeWindowController notificationShadeWindowController);
+
+ @Binds
+ abstract DozeHost bindDozeHost(DozeServiceHost dozeServiceHost);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index baa6ac9..ab61b44 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -171,6 +171,7 @@
mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false);
mCarNavigationBarController.showAllKeyguardButtons(/* isSetUp= */ true);
start();
+ getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ true);
reset(/* hideBouncerWhenShowing= */ false);
notifyKeyguardUpdateMonitor();
}
@@ -185,8 +186,9 @@
mBouncer.hide(/* destroyView= */ true);
mCarNavigationBarController.hideAllKeyguardButtons(/* isSetUp= */ true);
stop();
+ getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ false);
mKeyguardStateController.notifyKeyguardDoneFading();
- mViewMediatorCallback.keyguardGone();
+ mHandler.post(mViewMediatorCallback::keyguardGone);
notifyKeyguardUpdateMonitor();
}
@@ -201,6 +203,11 @@
}
mKeyguardUpdateMonitor.sendKeyguardReset();
notifyKeyguardUpdateMonitor();
+ } else {
+ // This is necessary in order to address an inconsistency between the keyguard service
+ // and the keyguard views.
+ // TODO: Investigate the source of the inconsistency.
+ show(/* options= */ null);
}
}
@@ -213,7 +220,7 @@
@Override
public void onCancelClicked() {
- if (!mShowing) return;
+ if (mBouncer == null) return;
getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ false);
getOverlayViewGlobalStateController().setWindowNeedsInput(/* needsInput= */ false);
@@ -229,19 +236,20 @@
@Override
public void dismissAndCollapse() {
- hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
+ if (!mBouncer.isSecure()) {
+ hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
+ }
}
@Override
public void startPreHideAnimation(Runnable finishRunnable) {
- if (!mShowing) return;
+ if (mBouncer == null) return;
mBouncer.startPreHideAnimation(finishRunnable);
}
@Override
public void setNeedsInput(boolean needsInput) {
- getOverlayViewGlobalStateController().setWindowFocusable(needsInput);
getOverlayViewGlobalStateController().setWindowNeedsInput(needsInput);
}
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 893efdc..5c6472e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,9 +16,12 @@
package com.android.systemui.car.navigationbar;
+import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
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;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
@@ -34,26 +37,31 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsetsController;
import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
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;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BarTransitions;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
+import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.FileDescriptor;
@@ -69,6 +77,7 @@
private final Resources mResources;
private final CarNavigationBarController mCarNavigationBarController;
+ private final SysuiDarkIconDispatcher mStatusBarIconController;
private final WindowManager mWindowManager;
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
private final CommandQueue mCommandQueue;
@@ -106,6 +115,7 @@
private boolean mDeviceIsSetUpForUser = true;
private boolean mIsUserSetupInProgress = false;
+ private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
@BarTransitions.TransitionMode
private int mStatusBarMode;
@BarTransitions.TransitionMode
@@ -117,6 +127,9 @@
public CarNavigationBar(Context context,
@Main Resources resources,
CarNavigationBarController carNavigationBarController,
+ // TODO(b/156052638): Should not need to inject LightBarController
+ LightBarController lightBarController,
+ DarkIconDispatcher darkIconDispatcher,
WindowManager windowManager,
CarDeviceProvisionedController deviceProvisionedController,
CommandQueue commandQueue,
@@ -133,6 +146,7 @@
super(context);
mResources = resources;
mCarNavigationBarController = carNavigationBarController;
+ mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
mWindowManager = windowManager;
mCarDeviceProvisionedController = deviceProvisionedController;
mCommandQueue = commandQueue;
@@ -166,6 +180,9 @@
ex.rethrowFromSystemServer();
}
+ onSystemBarAppearanceChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
+ result.mNavbarColorManagedByIme);
+
// StatusBarManagerService has a back up of IME token and it's restored here.
setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
result.mImeBackDisposition, result.mShowImeSwitcher);
@@ -362,7 +379,7 @@
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("TopCarNavigationBar");
- lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
+ lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
lp.setFitInsetsTypes(0);
lp.windowAnimations = 0;
lp.gravity = Gravity.TOP;
@@ -384,7 +401,7 @@
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("BottomCarNavigationBar");
- lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
lp.windowAnimations = 0;
lp.gravity = Gravity.BOTTOM;
mWindowManager.addView(mBottomNavigationBarWindow, lp);
@@ -447,6 +464,64 @@
}
@Override
+ public void onSystemBarAppearanceChanged(
+ int displayId,
+ @WindowInsetsController.Appearance int appearance,
+ AppearanceRegion[] appearanceRegions,
+ boolean navbarColorManagedByIme) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ boolean barModeChanged = updateStatusBarMode(
+ mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
+ int numStacks = appearanceRegions.length;
+ boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks;
+ for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) {
+ stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]);
+ }
+ if (stackAppearancesChanged || barModeChanged) {
+ mAppearanceRegions = appearanceRegions;
+ updateStatusBarAppearance();
+ }
+ }
+
+ private void updateStatusBarAppearance() {
+ int numStacks = mAppearanceRegions.length;
+ int numLightStacks = 0;
+
+ // We can only have maximum one light stack.
+ int indexLightStack = -1;
+
+ for (int i = 0; i < numStacks; i++) {
+ if (isLight(mAppearanceRegions[i].getAppearance())) {
+ numLightStacks++;
+ indexLightStack = i;
+ }
+ }
+
+ // If all stacks are light, all icons become dark.
+ if (numLightStacks == numStacks) {
+ mStatusBarIconController.setIconsDarkArea(null);
+ mStatusBarIconController.getTransitionsController().setIconsDark(
+ /* dark= */ true, /* animate= */ false);
+ } else if (numLightStacks == 0) {
+ // If no one is light, all icons become white.
+ mStatusBarIconController.getTransitionsController().setIconsDark(
+ /* dark= */ false, /* animate= */ false);
+ } else {
+ // Not the same for every stack, update icons in area only.
+ mStatusBarIconController.setIconsDarkArea(
+ mAppearanceRegions[indexLightStack].getBounds());
+ mStatusBarIconController.getTransitionsController().setIconsDark(
+ /* dark= */ true, /* animate= */ false);
+ }
+ }
+
+ private static boolean isLight(int appearance) {
+ return (appearance & APPEARANCE_LIGHT_STATUS_BARS) != 0;
+ }
+
+ @Override
public void showTransient(int displayId, int[] types) {
if (displayId != mDisplayId) {
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 9e194fb..288e5cf 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -73,7 +73,7 @@
}
/**
- * Hides all navigation bars.
+ * Hides all system bars.
*/
public void hideBars() {
if (mTopView != null) {
@@ -85,7 +85,7 @@
}
/**
- * Shows all navigation bars.
+ * Shows all system bars.
*/
public void showBars() {
if (mTopView != null) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
index 20fcca0..aeb1d39 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -29,41 +29,40 @@
import com.android.car.notification.R;
import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
* A controller for SysUI's HUN display.
*/
@Singleton
public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotificationContainer {
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final Lazy<NotificationPanelViewController> mNotificationPanelViewControllerLazy;
+ private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
private final ViewGroup mWindow;
private final FrameLayout mHeadsUpContentFrame;
- private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
-
@Inject
CarHeadsUpNotificationSystemContainer(Context context,
@Main Resources resources,
CarDeviceProvisionedController deviceProvisionedController,
WindowManager windowManager,
- Lazy<NotificationPanelViewController> notificationPanelViewControllerLazy) {
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
mCarDeviceProvisionedController = deviceProvisionedController;
- mNotificationPanelViewControllerLazy = notificationPanelViewControllerLazy;
+ mOverlayViewGlobalStateController = overlayViewGlobalStateController;
boolean showOnBottom = resources.getBoolean(R.bool.config_showHeadsUpNotificationOnBottom);
+ // Use TYPE_STATUS_BAR_SUB_PANEL window type since we need to find a window that is above
+ // status bar but below navigation bar.
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
@@ -78,15 +77,11 @@
windowManager.addView(mWindow, lp);
mWindow.setVisibility(View.INVISIBLE);
mHeadsUpContentFrame = mWindow.findViewById(R.id.headsup_content);
-
- mEnableHeadsUpNotificationWhenNotificationShadeOpen = resources.getBoolean(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen);
}
private void animateShow() {
- if ((mEnableHeadsUpNotificationWhenNotificationShadeOpen
- || !mNotificationPanelViewControllerLazy.get().isPanelExpanded())
- && mCarDeviceProvisionedController.isCurrentUserFullySetup()) {
+ if (mCarDeviceProvisionedController.isCurrentUserFullySetup()
+ && mOverlayViewGlobalStateController.shouldShowHUN()) {
mWindow.setVisibility(View.VISIBLE);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index cb9539a..1738091 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -73,6 +73,7 @@
private final CarNotificationListener mCarNotificationListener;
private final NotificationClickHandlerFactory mNotificationClickHandlerFactory;
private final StatusBarStateController mStatusBarStateController;
+ private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
private float mInitialBackgroundAlpha;
private float mBackgroundAlphaDiff;
@@ -144,6 +145,10 @@
+ " percentage");
}
mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha;
+
+ mEnableHeadsUpNotificationWhenNotificationShadeOpen = mResources.getBoolean(
+ com.android.car.notification.R.bool
+ .config_enableHeadsUpNotificationWhenNotificationShadeOpen);
}
@Override
@@ -151,6 +156,16 @@
reinflate();
}
+ @Override
+ protected boolean shouldShowNavigationBar() {
+ return true;
+ }
+
+ @Override
+ protected boolean shouldShowHUN() {
+ return mEnableHeadsUpNotificationWhenNotificationShadeOpen;
+ }
+
/** Reinflates the view. */
public void reinflate() {
ViewGroup container = (ViewGroup) getLayout();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
index 8f52638..41349b2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
@@ -26,8 +26,15 @@
import com.android.systemui.car.window.OverlayViewMediator;
import com.android.systemui.statusbar.policy.ConfigurationController;
-/** The view mediator which attaches the view controller to other elements of the system ui. */
-public abstract class NotificationPanelViewMediator implements OverlayViewMediator,
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * The view mediator which attaches the view controller to other elements of the system ui. Disables
+ * drag open behavior of the notification panel from any navigation bar.
+ */
+@Singleton
+public class NotificationPanelViewMediator implements OverlayViewMediator,
ConfigurationController.ConfigurationListener {
private final CarNavigationBarController mCarNavigationBarController;
@@ -36,6 +43,7 @@
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
private final ConfigurationController mConfigurationController;
+ @Inject
public NotificationPanelViewMediator(
CarNavigationBarController carNavigationBarController,
NotificationPanelViewController notificationPanelViewController,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java
index e2eb3fb..d18eadd 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java
@@ -425,6 +425,11 @@
}
@Override
+ public void notifyBiometricAuthModeChanged() {
+ // No op.
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
//When executing dump() function simultaneously, we need to serialize them
//to get mStackScroller's position correctly.
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java
new file mode 100644
index 0000000..d23660c
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java
@@ -0,0 +1,130 @@
+/*
+ * 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.statusbar;
+
+import com.android.systemui.doze.DozeHost;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** No-op implementation of {@link DozeHost} for use by car sysui, which does not support dozing. */
+@Singleton
+public class DozeServiceHost implements DozeHost {
+
+ @Inject
+ public DozeServiceHost() {}
+
+ @Override
+ public void addCallback(Callback callback) {
+ // No op.
+ }
+
+ @Override
+ public void removeCallback(Callback callback) {
+ // No op.
+ }
+
+ @Override
+ public void startDozing() {
+ // No op.
+ }
+
+ @Override
+ public void pulseWhileDozing(PulseCallback callback, int reason) {
+ // No op.
+ }
+
+ @Override
+ public void stopDozing() {
+ // No op.
+ }
+
+ @Override
+ public void dozeTimeTick() {
+ // No op.
+ }
+
+ @Override
+ public boolean isPowerSaveActive() {
+ return false;
+ }
+
+ @Override
+ public boolean isPulsingBlocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isProvisioned() {
+ return false;
+ }
+
+ @Override
+ public boolean isBlockingDoze() {
+ return true;
+ }
+
+ @Override
+ public void extendPulse(int reason) {
+ // No op.
+ }
+
+ @Override
+ public void setAnimateWakeup(boolean animateWakeup) {
+ // No op.
+ }
+
+ @Override
+ public void setAnimateScreenOff(boolean animateScreenOff) {
+ // No op.
+ }
+
+ @Override
+ public void onSlpiTap(float x, float y) {
+ // No op.
+ }
+
+ @Override
+ public void setDozeScreenBrightness(int value) {
+ // No op.
+ }
+
+ @Override
+ public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
+ // No op.
+ }
+
+ @Override
+ public void cancelGentleSleep() {
+ // No op.
+ }
+
+ @Override
+ public void onIgnoreTouchWhilePulsing(boolean ignore) {
+ // No op.
+ }
+
+ @Override
+ public void stopPulsing() {
+ // No op.
+ }
+
+ @Override
+ public boolean isDozeSuppressed() {
+ return true;
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
index 346c38c..8b399f8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
@@ -34,16 +34,19 @@
private final StatusBarStateController mStatusBarStateController;
private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController;
private final CarKeyguardViewController mCarKeyguardViewController;
+ private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
@Inject
public FullscreenUserSwitcherViewMediator(
StatusBarStateController statusBarStateController,
CarKeyguardViewController carKeyguardViewController,
+ UserSwitchTransitionViewController userSwitchTransitionViewController,
FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController) {
mStatusBarStateController = statusBarStateController;
- mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
mCarKeyguardViewController = carKeyguardViewController;
+ mUserSwitchTransitionViewController = userSwitchTransitionViewController;
+ mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
}
@Override
@@ -74,6 +77,11 @@
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
if (record.mType != UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
mCarKeyguardViewController.hideKeyguardToPrepareBouncer();
+ // If guest user, we cannot use record.mInfo.id and should listen to the User lifecycle
+ // event instead.
+ if (record.mType != UserGridRecyclerView.UserRecord.START_GUEST) {
+ mUserSwitchTransitionViewController.handleShow(record.mInfo.id);
+ }
}
hide();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
new file mode 100644
index 0000000..775ef81
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
@@ -0,0 +1,126 @@
+/*
+ * 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.userswitcher;
+
+import static android.car.settings.CarSettings.Global.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE;
+
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.settingslib.drawable.CircleFramedDrawable;
+import com.android.systemui.R;
+import com.android.systemui.car.window.OverlayViewController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles showing and hiding UserSwitchTransitionView that is mounted to SystemUiOverlayWindow.
+ */
+@Singleton
+public class UserSwitchTransitionViewController extends OverlayViewController {
+ private static final String TAG = "UserSwitchTransitionViewController";
+ private static final String ENABLE_DEVELOPER_MESSAGE_TRUE = "true";
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Resources mResources;
+ private final UserManager mUserManager;
+
+ @GuardedBy("this")
+ private boolean mShowing;
+ private int mPreviousUserId = UserHandle.USER_NULL;
+
+ @Inject
+ public UserSwitchTransitionViewController(
+ Context context,
+ @Main Handler handler,
+ @Main Resources resources,
+ UserManager userManager,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+
+ super(R.id.user_switching_dialog_stub, overlayViewGlobalStateController);
+
+ mContext = context;
+ mHandler = handler;
+ mResources = resources;
+ mUserManager = userManager;
+ }
+
+ /**
+ * Makes the user switch transition view appear and draws the content inside of it if a user
+ * that is different from the previous user is provided and if the dialog is not already
+ * showing.
+ */
+ void handleShow(@UserIdInt int newUserId) {
+ if (mPreviousUserId == newUserId || mShowing) return;
+ mShowing = true;
+ mHandler.post(() -> {
+ start();
+ populateDialog(mPreviousUserId, newUserId);
+ // next time a new user is selected, this current new user will be the previous user.
+ mPreviousUserId = newUserId;
+ });
+ }
+
+ void handleHide() {
+ if (!mShowing) return;
+ mShowing = false;
+ mHandler.post(this::stop);
+ }
+
+ private void populateDialog(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
+ drawUserIcon(newUserId);
+ populateLoadingText(previousUserId, newUserId);
+ }
+
+ private void drawUserIcon(int newUserId) {
+ Bitmap bitmap = mUserManager.getUserIcon(newUserId);
+ if (bitmap != null) {
+ CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(mContext, bitmap);
+ ((ImageView) getLayout().findViewById(R.id.user_loading_avatar))
+ .setImageDrawable(drawable);
+ }
+ }
+
+ private void populateLoadingText(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
+ TextView msgView = getLayout().findViewById(R.id.user_loading);
+
+ boolean showInfo = ENABLE_DEVELOPER_MESSAGE_TRUE.equals(
+ Settings.Global.getString(mContext.getContentResolver(),
+ ENABLE_USER_SWITCH_DEVELOPER_MESSAGE));
+
+ if (showInfo && mPreviousUserId != UserHandle.USER_NULL) {
+ msgView.setText(
+ mResources.getString(R.string.car_loading_profile_developer_message,
+ previousUserId, newUserId));
+ } else {
+ msgView.setText(mResources.getString(R.string.car_loading_profile));
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
new file mode 100644
index 0000000..aea6914
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
@@ -0,0 +1,85 @@
+/*
+ * 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.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.CarServiceProvider;
+import com.android.systemui.car.window.OverlayViewMediator;
+
+import javax.inject.Inject;
+
+/**
+ * Registers listeners that subscribe to events that show or hide CarUserSwitchingDialog that is
+ * mounted to SystemUiOverlayWindow.
+ */
+public class UserSwitchTransitionViewMediator implements OverlayViewMediator,
+ CarUserManager.UserSwitchUiCallback {
+ private static final String TAG = "UserSwitchTransitionViewMediator";
+
+ private final CarServiceProvider mCarServiceProvider;
+ private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
+
+ @Inject
+ public UserSwitchTransitionViewMediator(
+ CarServiceProvider carServiceProvider,
+ UserSwitchTransitionViewController userSwitchTransitionViewController) {
+ mCarServiceProvider = carServiceProvider;
+ mUserSwitchTransitionViewController = userSwitchTransitionViewController;
+ }
+
+ @Override
+ public void registerListeners() {
+ mCarServiceProvider.addListener(car -> {
+ CarUserManager carUserManager =
+ (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+
+ if (carUserManager != null) {
+ carUserManager.setUserSwitchUiCallback(this);
+ carUserManager.addListener(Runnable::run, this::handleUserLifecycleEvent);
+ } else {
+ Log.e(TAG, "registerListeners: CarUserManager could not be obtained.");
+ }
+ });
+ }
+
+ @Override
+ public void setupOverlayContentViewControllers() {
+ // no-op.
+ }
+
+ @Override
+ public void showUserSwitchDialog(int userId) {
+ mUserSwitchTransitionViewController.handleShow(userId);
+ }
+
+ @VisibleForTesting
+ void handleUserLifecycleEvent(CarUserManager.UserLifecycleEvent event) {
+ if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING
+ && ActivityManager.getCurrentUser() == event.getUserId()) {
+ mUserSwitchTransitionViewController.handleShow(event.getUserId());
+ }
+
+ if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+ mUserSwitchTransitionViewController.handleHide();
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java
index 2bdb85f..03b61e0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java
@@ -52,6 +52,15 @@
new CarAudioManager.CarVolumeCallback() {
@Override
public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
+ initVolumeDialogComponent();
+ }
+
+ @Override
+ public void onMasterMuteChanged(int zoneId, int flags) {
+ initVolumeDialogComponent();
+ }
+
+ private void initVolumeDialogComponent() {
if (mVolumeDialogComponent == null) {
mMainHandler.post(() -> {
mVolumeDialogComponent = mVolumeDialogComponentLazy.get();
@@ -60,11 +69,6 @@
mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
}
}
-
- @Override
- public void onMasterMuteChanged(int zoneId, int flags) {
- // ignored
- }
};
private boolean mEnabled;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 0fe9856..45808a8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -375,10 +375,10 @@
}
if (visible && !getOverlayViewGlobalStateController().isWindowVisible()) {
- getOverlayViewGlobalStateController().setWindowVisible(true);
+ getOverlayViewGlobalStateController().showView(/* panelViewController= */ this);
}
if (!visible && getOverlayViewGlobalStateController().isWindowVisible()) {
- getOverlayViewGlobalStateController().setWindowVisible(false);
+ getOverlayViewGlobalStateController().hideView(/* panelViewController= */ this);
}
getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
getOverlayViewGlobalStateController().setWindowFocusable(visible);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
index 87f2020..30e2657 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
@@ -54,7 +54,6 @@
mOverlayViewGlobalStateController.hideView(/* viewController= */ this, this::hide);
}
-
/**
* Inflate layout owned by controller.
*/
@@ -72,7 +71,7 @@
}
/**
- * Returns [@code true} if layout owned by controller has been inflated.
+ * Returns {@code true} if layout owned by controller has been inflated.
*/
public final boolean isInflated() {
return mLayout != null;
@@ -125,4 +124,18 @@
protected final OverlayViewGlobalStateController getOverlayViewGlobalStateController() {
return mOverlayViewGlobalStateController;
}
+
+ /**
+ * Returns {@code true} if heads up notifications should be displayed over this view.
+ */
+ protected boolean shouldShowHUN() {
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if navigation bar should be displayed over this view.
+ */
+ protected boolean shouldShowNavigationBar() {
+ return false;
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
index 290505f..70260b0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
@@ -16,14 +16,17 @@
package com.android.systemui.car.window;
+import android.annotation.Nullable;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -39,11 +42,17 @@
*/
@Singleton
public class OverlayViewGlobalStateController {
+ private static final boolean DEBUG = false;
private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName();
+ private static final int UNKNOWN_Z_ORDER = -1;
private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
private final CarNavigationBarController mCarNavigationBarController;
@VisibleForTesting
- Set<String> mShownSet;
+ Map<OverlayViewController, Integer> mZOrderMap;
+ @VisibleForTesting
+ SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
+ @VisibleForTesting
+ OverlayViewController mHighestZOrder;
@Inject
public OverlayViewGlobalStateController(
@@ -52,7 +61,8 @@
mSystemUIOverlayWindowController = systemUIOverlayWindowController;
mSystemUIOverlayWindowController.attach();
mCarNavigationBarController = carNavigationBarController;
- mShownSet = new HashSet<>();
+ mZOrderMap = new HashMap<>();
+ mZOrderVisibleSortedMap = new TreeMap<>();
}
/**
@@ -66,51 +76,127 @@
}
/**
- * Show content in Overlay Window.
+ * Show content in Overlay Window using {@link OverlayPanelViewController}.
+ *
+ * This calls {@link OverlayViewGlobalStateController#showView(OverlayViewController, Runnable)}
+ * where the runnable is nullified since the actual showing of the panel is handled by the
+ * controller itself.
*/
- public void showView(OverlayViewController viewController, Runnable show) {
- if (mShownSet.isEmpty()) {
- mCarNavigationBarController.hideBars();
- setWindowVisible(true);
- }
-
- inflateView(viewController);
-
- show.run();
- mShownSet.add(viewController.getClass().getName());
-
- Log.d(TAG, "Content shown: " + viewController.getClass().getName());
+ public void showView(OverlayPanelViewController panelViewController) {
+ showView(panelViewController, /* show= */ null);
}
/**
- * Hide content in Overlay Window.
+ * Show content in Overlay Window using {@link OverlayViewController}.
*/
- public void hideView(OverlayViewController viewController, Runnable hide) {
+ public void showView(OverlayViewController viewController, @Nullable Runnable show) {
+ debugLog();
+ if (mZOrderVisibleSortedMap.isEmpty()) {
+ setWindowVisible(true);
+ }
+ if (!(viewController instanceof OverlayPanelViewController)) {
+ inflateView(viewController);
+ }
+
+ if (show != null) {
+ show.run();
+ }
+
+ updateInternalsWhenShowingView(viewController);
+ refreshNavigationBarVisibility();
+
+ Log.d(TAG, "Content shown: " + viewController.getClass().getName());
+ debugLog();
+ }
+
+ private void updateInternalsWhenShowingView(OverlayViewController viewController) {
+ int zOrder;
+ if (mZOrderMap.containsKey(viewController)) {
+ zOrder = mZOrderMap.get(viewController);
+ } else {
+ zOrder = mSystemUIOverlayWindowController.getBaseLayout().indexOfChild(
+ viewController.getLayout());
+ mZOrderMap.put(viewController, zOrder);
+ }
+
+ mZOrderVisibleSortedMap.put(zOrder, viewController);
+
+ refreshHighestZOrderWhenShowingView(viewController);
+ }
+
+ private void refreshHighestZOrderWhenShowingView(OverlayViewController viewController) {
+ if (mZOrderMap.getOrDefault(mHighestZOrder, UNKNOWN_Z_ORDER) < mZOrderMap.get(
+ viewController)) {
+ mHighestZOrder = viewController;
+ }
+ }
+
+ /**
+ * Hide content in Overlay Window using {@link OverlayPanelViewController}.
+ *
+ * This calls {@link OverlayViewGlobalStateController#hideView(OverlayViewController, Runnable)}
+ * where the runnable is nullified since the actual hiding of the panel is handled by the
+ * controller itself.
+ */
+ public void hideView(OverlayPanelViewController panelViewController) {
+ hideView(panelViewController, /* hide= */ null);
+ }
+
+ /**
+ * Hide content in Overlay Window using {@link OverlayViewController}.
+ */
+ public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
+ debugLog();
if (!viewController.isInflated()) {
Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
+ viewController.getClass().getName());
return;
}
- if (!mShownSet.contains(viewController.getClass().getName())) {
- Log.d(TAG, "Content cannot be hidden since it isn't shown: "
+ if (!mZOrderMap.containsKey(viewController)) {
+ Log.d(TAG, "Content cannot be hidden since it has never been shown: "
+ + viewController.getClass().getName());
+ return;
+ }
+ if (!mZOrderVisibleSortedMap.containsKey(mZOrderMap.get(viewController))) {
+ Log.d(TAG, "Content cannot be hidden since it isn't currently shown: "
+ viewController.getClass().getName());
return;
}
- hide.run();
- mShownSet.remove(viewController.getClass().getName());
+ if (hide != null) {
+ hide.run();
+ }
- if (mShownSet.isEmpty()) {
- mCarNavigationBarController.showBars();
+ mZOrderVisibleSortedMap.remove(mZOrderMap.get(viewController));
+ refreshHighestZOrderWhenHidingView(viewController);
+ refreshNavigationBarVisibility();
+
+ if (mZOrderVisibleSortedMap.isEmpty()) {
setWindowVisible(false);
}
Log.d(TAG, "Content hidden: " + viewController.getClass().getName());
+ debugLog();
}
- /** Sets the window visibility state. */
- public void setWindowVisible(boolean expanded) {
- mSystemUIOverlayWindowController.setWindowVisible(expanded);
+ private void refreshHighestZOrderWhenHidingView(OverlayViewController viewController) {
+ if (mZOrderVisibleSortedMap.isEmpty()) {
+ mHighestZOrder = null;
+ return;
+ }
+ if (!mHighestZOrder.equals(viewController)) {
+ return;
+ }
+
+ mHighestZOrder = mZOrderVisibleSortedMap.get(mZOrderVisibleSortedMap.lastKey());
+ }
+
+ private void refreshNavigationBarVisibility() {
+ if (mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowNavigationBar()) {
+ mCarNavigationBarController.showBars();
+ } else {
+ mCarNavigationBarController.hideBars();
+ }
}
/** Returns {@code true} is the window is visible. */
@@ -118,13 +204,14 @@
return mSystemUIOverlayWindowController.isWindowVisible();
}
- /** Sets the focusable flag of the sysui overlawy window. */
- public void setWindowFocusable(boolean focusable) {
- mSystemUIOverlayWindowController.setWindowFocusable(focusable);
+ private void setWindowVisible(boolean visible) {
+ mSystemUIOverlayWindowController.setWindowVisible(visible);
}
- /** Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the
- * sysui overlay window */
+ /**
+ * Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the
+ * sysui overlay window.
+ */
public void setWindowNeedsInput(boolean needsInput) {
mSystemUIOverlayWindowController.setWindowNeedsInput(needsInput);
}
@@ -134,10 +221,34 @@
return mSystemUIOverlayWindowController.isWindowFocusable();
}
+ /** Sets the focusable flag of the sysui overlawy window. */
+ public void setWindowFocusable(boolean focusable) {
+ mSystemUIOverlayWindowController.setWindowFocusable(focusable);
+ }
+
/** Inflates the view controlled by the given view controller. */
public void inflateView(OverlayViewController viewController) {
if (!viewController.isInflated()) {
viewController.inflate(mSystemUIOverlayWindowController.getBaseLayout());
}
}
+
+ /**
+ * Return {@code true} if OverlayWindow is in a state where HUNs should be displayed above it.
+ */
+ public boolean shouldShowHUN() {
+ return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
+ }
+
+ private void debugLog() {
+ if (!DEBUG) {
+ return;
+ }
+
+ Log.d(TAG, "mHighestZOrder: " + mHighestZOrder);
+ Log.d(TAG, "mZOrderVisibleSortedMap.size(): " + mZOrderVisibleSortedMap.size());
+ Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
+ Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
+ Log.d(TAG, "mZOrderMap: " + mZOrderMap);
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
index ac574ed..3e7b4a2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
@@ -23,6 +23,9 @@
/**
* Register listeners that could use ContentVisibilityAdjuster to show/hide content.
+ *
+ * Note that we do not unregister listeners because SystemUI components are expected to live
+ * for the lifecycle of the device.
*/
void registerListeners();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
index e1918ce..5a16efa 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
@@ -18,8 +18,10 @@
import com.android.systemui.car.keyguard.CarKeyguardViewMediator;
import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
+import com.android.systemui.car.notification.NotificationPanelViewMediator;
import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
+import com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator;
import dagger.Binds;
import dagger.Module;
@@ -32,6 +34,13 @@
@Module
public abstract class OverlayWindowModule {
+ /** Injects NotificationPanelViewMediator. */
+ @Binds
+ @IntoMap
+ @ClassKey(NotificationPanelViewMediator.class)
+ public abstract OverlayViewMediator bindNotificationPanelViewMediator(
+ NotificationPanelViewMediator notificationPanelViewMediator);
+
/** Injects TopNotificationPanelViewMediator. */
@Binds
@IntoMap
@@ -59,4 +68,11 @@
@ClassKey(FullscreenUserSwitcherViewMediator.class)
public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator(
FullscreenUserSwitcherViewMediator overlayViewsMediator);
+
+ /** Injects CarUserSwitchingDialogMediator. */
+ @Binds
+ @IntoMap
+ @ClassKey(UserSwitchTransitionViewMediator.class)
+ public abstract OverlayViewMediator bindUserSwitchTransitionViewMediator(
+ UserSwitchTransitionViewMediator userSwitchTransitionViewMediator);
}
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml
new file mode 100644
index 0000000..03fe0e4
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml
@@ -0,0 +1,43 @@
+<?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.
+ -->
+
+<!-- Fullscreen views in sysui should be listed here in increasing Z order. -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@android:color/transparent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub_1"
+ android:inflatedId="@+id/overlay_view_controller_1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub_2"
+ android:inflatedId="@+id/overlay_view_controller_2"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub_3"
+ android:inflatedId="@+id/overlay_view_controller_3"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index a2192af..38836d8 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -16,9 +16,10 @@
package com.android.systemui.car.keyguard;
-import static com.google.common.truth.Truth.assertThat;
-
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -29,9 +30,10 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
+import androidx.test.filters.SmallTest;
+
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
@@ -40,7 +42,6 @@
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.car.window.SystemUIOverlayWindowController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
@@ -51,6 +52,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -58,31 +60,24 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
+@SmallTest
public class CarKeyguardViewControllerTest extends SysuiTestCase {
private TestableCarKeyguardViewController mCarKeyguardViewController;
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- private ViewGroup mBaseLayout;
@Mock
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+ @Mock
private KeyguardBouncer mBouncer;
@Mock
private CarNavigationBarController mCarNavigationBarController;
@Mock
- private SystemUIOverlayWindowController mSystemUIOverlayWindowController;
- @Mock
private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
- mCarNavigationBarController, mSystemUIOverlayWindowController);
- mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.sysui_overlay_window, /* root= */ null);
- when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
-
mCarKeyguardViewController = new TestableCarKeyguardViewController(
mContext,
Handler.getMain(),
@@ -98,6 +93,8 @@
mock(FalsingManager.class),
() -> mock(KeyguardBypassController.class)
);
+ mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.sysui_overlay_window, /* root= */ null));
}
@Test
@@ -113,8 +110,7 @@
when(mBouncer.isSecure()).thenReturn(true);
mCarKeyguardViewController.show(/* options= */ null);
- assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo(
- View.VISIBLE);
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController), any());
}
@Test
@@ -130,8 +126,17 @@
when(mBouncer.isSecure()).thenReturn(false);
mCarKeyguardViewController.show(/* options= */ null);
- assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo(
- View.GONE);
+ // Here we check for both showView and hideView since the current implementation of show
+ // with bouncer being not secure has the following method execution orders:
+ // 1) show -> start -> showView
+ // 2) show -> reset -> dismissAndCollapse -> hide -> stop -> hideView
+ // Hence, we want to make sure that showView is called before hideView and not in any
+ // other combination.
+ InOrder inOrder = inOrder(mOverlayViewGlobalStateController);
+ inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController),
+ any());
+ inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController),
+ any());
}
@Test
@@ -156,8 +161,11 @@
mCarKeyguardViewController.show(/* options= */ null);
mCarKeyguardViewController.hide(/* startTime= */ 0, /* fadeoutDelay= */ 0);
- assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo(
- View.GONE);
+ InOrder inOrder = inOrder(mOverlayViewGlobalStateController);
+ inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController),
+ any());
+ inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController),
+ any());
}
@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 77eecac..04e0a73 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
@@ -18,6 +18,8 @@
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static com.google.common.truth.Truth.assertThat;
@@ -25,6 +27,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
@@ -44,8 +47,11 @@
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -69,6 +75,12 @@
@Mock
private CarNavigationBarController mCarNavigationBarController;
@Mock
+ private LightBarController mLightBarController;
+ @Mock
+ private SysuiDarkIconDispatcher mStatusBarIconController;
+ @Mock
+ private LightBarTransitionsController mLightBarTransitionsController;
+ @Mock
private WindowManager mWindowManager;
@Mock
private CarDeviceProvisionedController mDeviceProvisionedController;
@@ -88,6 +100,7 @@
private StatusBarIconController mIconController;
private RegisterStatusBarResult mBarResult;
+ private AppearanceRegion[] mAppearanceRegions;
private FakeExecutor mUiBgExecutor;
@Before
@@ -96,11 +109,16 @@
mTestableResources = mContext.getOrCreateTestableResources();
mHandler = Handler.getMain();
mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+ when(mStatusBarIconController.getTransitionsController()).thenReturn(
+ mLightBarTransitionsController);
+ mAppearanceRegions = new AppearanceRegion[] {
+ new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect())
+ };
mBarResult = new RegisterStatusBarResult(
/* icons= */ new ArrayMap<>(),
/* disabledFlags1= */ 0,
/* appearance= */ 0,
- /* appearanceRegions= */ new AppearanceRegion[]{},
+ mAppearanceRegions,
/* imeWindowVis= */ 0,
/* imeBackDisposition= */ 0,
/* showImeSwitcher= */ false,
@@ -116,10 +134,11 @@
e.printStackTrace();
}
mCarNavigationBar = new CarNavigationBar(mContext, mTestableResources.getResources(),
- mCarNavigationBarController, mWindowManager, mDeviceProvisionedController,
- new CommandQueue(mContext), mAutoHideController, mButtonSelectionStateListener,
- mHandler, mUiBgExecutor, mBarService, () -> mKeyguardStateController,
- mButtonSelectionStateController, () -> mIconPolicy, () -> mIconController);
+ mCarNavigationBarController, mLightBarController, mStatusBarIconController,
+ mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext),
+ mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor,
+ mBarService, () -> mKeyguardStateController, mButtonSelectionStateController,
+ () -> mIconPolicy, () -> mIconController);
}
@Test
@@ -186,6 +205,26 @@
}
@Test
+ public void restartNavBars_lightAppearance_darkensAllIcons() {
+ mAppearanceRegions[0] = new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect());
+
+ mCarNavigationBar.start();
+
+ verify(mLightBarTransitionsController).setIconsDark(
+ /* dark= */ true, /* animate= */ false);
+ }
+
+ @Test
+ public void restartNavBars_opaqueAppearance_lightensAllIcons() {
+ mAppearanceRegions[0] = new AppearanceRegion(APPEARANCE_OPAQUE_STATUS_BARS, new Rect());
+
+ mCarNavigationBar.start();
+
+ verify(mLightBarTransitionsController).setIconsDark(
+ /* dark= */ false, /* animate= */ false);
+ }
+
+ @Test
public void showTransient_wrongDisplayId_transientModeNotUpdated() {
mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
index 6ac72a6..ccaeb45 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
@@ -28,9 +28,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
import org.junit.Before;
import org.junit.Test;
@@ -42,12 +42,11 @@
@TestableLooper.RunWithLooper
@SmallTest
public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase {
- private CarHeadsUpNotificationSystemContainer mDefaultController;
- private CarHeadsUpNotificationSystemContainer mOverrideEnabledController;
+ private CarHeadsUpNotificationSystemContainer mCarHeadsUpNotificationSystemContainer;
@Mock
private CarDeviceProvisionedController mCarDeviceProvisionedController;
@Mock
- private NotificationPanelViewController mNotificationPanelViewController;
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
@Mock
private WindowManager mWindowManager;
@@ -58,76 +57,63 @@
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ MockitoAnnotations.initMocks(/* testClass= */this);
- when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(false);
- when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(false);
+ when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(true);
+ when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
TestableResources testableResources = mContext.getOrCreateTestableResources();
- testableResources.addOverride(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, false);
-
- mDefaultController = new CarHeadsUpNotificationSystemContainer(mContext,
+ mCarHeadsUpNotificationSystemContainer = new CarHeadsUpNotificationSystemContainer(mContext,
testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
- () -> mNotificationPanelViewController);
-
- testableResources.addOverride(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, true);
-
- mOverrideEnabledController = new CarHeadsUpNotificationSystemContainer(mContext,
- testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
- () -> mNotificationPanelViewController);
+ mOverlayViewGlobalStateController);
}
@Test
public void testDisplayNotification_firstNotification_isVisible() {
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isTrue();
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
@Test
public void testRemoveNotification_lastNotification_isInvisible() {
- mDefaultController.displayNotification(mNotificationView);
- mDefaultController.removeNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
}
@Test
public void testRemoveNotification_nonLastNotification_isVisible() {
- mDefaultController.displayNotification(mNotificationView);
- mDefaultController.displayNotification(mNotificationView2);
- mDefaultController.removeNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isTrue();
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView2);
+ mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
@Test
- public void testDisplayNotification_userSetupInProgress_isInvisible() {
- when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(true);
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ public void testDisplayNotification_userFullySetupTrue_isInvisible() {
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
@Test
- public void testDisplayNotification_userSetupIncomplete_isInvisible() {
- when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ public void testDisplayNotification_userFullySetupFalse_isInvisible() {
+ when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(false);
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
}
@Test
- public void testDisplayNotification_notificationPanelExpanded_isInvisible() {
- when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true);
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ public void testDisplayNotification_overlayWindowStateShouldShowHUNFalse_isInvisible() {
+ when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(false);
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
}
@Test
- public void testDisplayNotification_notificationPanelExpandedEnabledHUNWhenOpen_isVisible() {
- when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true);
- mOverrideEnabledController.displayNotification(mNotificationView);
- assertThat(mOverrideEnabledController.isVisible()).isTrue();
+ public void testDisplayNotification_overlayWindowStateShouldShowHUNTrue_isVisible() {
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
new file mode 100644
index 0000000..eab381c
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.userswitcher;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.UserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class UserSwitchTransitionViewControllerTest extends SysuiTestCase {
+ private static final int TEST_USER_1 = 100;
+ private static final int TEST_USER_2 = 110;
+
+ private TestableUserSwitchTransitionViewController mCarUserSwitchingDialogController;
+ private TestableResources mTestableResources;
+ @Mock
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTestableResources = mContext.getOrCreateTestableResources();
+ mCarUserSwitchingDialogController = new TestableUserSwitchTransitionViewController(
+ mContext,
+ Handler.getMain(),
+ mTestableResources.getResources(),
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE),
+ mOverlayViewGlobalStateController
+ );
+
+ mCarUserSwitchingDialogController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.sysui_overlay_window, /* root= */ null));
+ }
+
+ @Test
+ public void onHandleShow_newUserSelected_showsDialog() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHandleShow_alreadyShowing_ignoresRequest() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_2);
+
+ // Verify that the request was processed only once.
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHandleShow_sameUserSelected_ignoresRequest() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleHide();
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+
+ // Verify that the request was processed only once.
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHide_currentlyShowing_hidesDialog() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleHide();
+
+ verify(mOverlayViewGlobalStateController).hideView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHide_notShowing_ignoresRequest() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleHide();
+ mCarUserSwitchingDialogController.handleHide();
+
+ // Verify that the request was processed only once.
+ verify(mOverlayViewGlobalStateController).hideView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ private final class TestableUserSwitchTransitionViewController extends
+ UserSwitchTransitionViewController {
+
+ private final Handler mHandler;
+
+ TestableUserSwitchTransitionViewController(Context context, Handler handler,
+ Resources resources, UserManager userManager,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+ super(context, handler, resources, userManager, overlayViewGlobalStateController);
+ mHandler = handler;
+ }
+
+ @Override
+ public void handleShow(int currentUserId) {
+ super.handleShow(currentUserId);
+ waitForIdleSync(mHandler);
+ }
+
+ @Override
+ public void handleHide() {
+ super.handleHide();
+ waitForIdleSync(mHandler);
+ }
+ }
+}
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
new file mode 100644
index 0000000..a808e2d
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.userswitcher;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.user.CarUserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.car.CarServiceProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class UserSwitchTransitionViewMediatorTest {
+ private static final int TEST_USER = 100;
+
+ private UserSwitchTransitionViewMediator mUserSwitchTransitionViewMediator;
+ @Mock
+ private CarServiceProvider mCarServiceProvider;
+ @Mock
+ private UserSwitchTransitionViewController mUserSwitchTransitionViewController;
+ @Mock
+ private CarUserManager.UserLifecycleEvent mUserLifecycleEvent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mUserSwitchTransitionViewMediator = new UserSwitchTransitionViewMediator(
+ mCarServiceProvider, mUserSwitchTransitionViewController);
+
+ }
+
+ @Test
+ public void onUserLifecycleEvent_userStarting_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_userSwitching_callsHandleHide() {
+ when(mUserLifecycleEvent.getEventType()).thenReturn(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
+ mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
+
+ verify(mUserSwitchTransitionViewController).handleHide();
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
index 8d705a8..45a05ac 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
@@ -339,7 +339,7 @@
mOverlayPanelViewController.setPanelVisible(true);
- verify(mOverlayViewGlobalStateController).setWindowVisible(true);
+ verify(mOverlayViewGlobalStateController).showView(mOverlayPanelViewController);
}
@Test
@@ -349,7 +349,7 @@
mOverlayPanelViewController.setPanelVisible(true);
- verify(mOverlayViewGlobalStateController, never()).setWindowVisible(true);
+ verify(mOverlayViewGlobalStateController, never()).showView(mOverlayPanelViewController);
}
@Test
@@ -377,7 +377,7 @@
mOverlayPanelViewController.setPanelVisible(false);
- verify(mOverlayViewGlobalStateController).setWindowVisible(false);
+ verify(mOverlayViewGlobalStateController).hideView(mOverlayPanelViewController);
}
@Test
@@ -387,7 +387,7 @@
mOverlayPanelViewController.setPanelVisible(false);
- verify(mOverlayViewGlobalStateController, never()).setWindowVisible(false);
+ verify(mOverlayViewGlobalStateController, never()).hideView(mOverlayPanelViewController);
}
@Test
@@ -428,10 +428,6 @@
private static class TestOverlayPanelViewController extends OverlayPanelViewController {
- private boolean mShouldAnimateCollapsePanel;
- private boolean mShouldAnimateExpandPanel;
- private boolean mShouldAllowClosingScroll;
-
boolean mOnAnimateCollapsePanelCalled;
boolean mAnimateCollapsePanelCalled;
boolean mOnAnimateExpandPanelCalled;
@@ -440,6 +436,9 @@
boolean mOnExpandAnimationEndCalled;
boolean mOnOpenScrollStartEnd;
List<Integer> mOnScrollHeights;
+ private boolean mShouldAnimateCollapsePanel;
+ private boolean mShouldAnimateExpandPanel;
+ private boolean mShouldAllowClosingScroll;
TestOverlayPanelViewController(
Context context,
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index 25dd4f5..9e6e616 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -24,25 +24,33 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.view.ViewStub;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
+import com.android.systemui.tests.R;
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;
+import java.util.Arrays;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
- private static final String MOCK_OVERLAY_VIEW_CONTROLLER_NAME = "OverlayViewController";
+ private static final int OVERLAY_VIEW_CONTROLLER_1_Z_ORDER = 0;
+ private static final int OVERLAY_VIEW_CONTROLLER_2_Z_ORDER = 1;
+ private static final int OVERLAY_PANEL_VIEW_CONTROLLER_Z_ORDER = 2;
private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
private ViewGroup mBaseLayout;
@@ -54,7 +62,11 @@
@Mock
private OverlayViewMediator mOverlayViewMediator;
@Mock
- private OverlayViewController mOverlayViewController;
+ private OverlayViewController mOverlayViewController1;
+ @Mock
+ private OverlayViewController mOverlayViewController2;
+ @Mock
+ private OverlayPanelViewController mOverlayPanelViewController;
@Mock
private Runnable mRunnable;
@@ -62,14 +74,15 @@
public void setUp() {
MockitoAnnotations.initMocks(/* testClass= */ this);
+ mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.overlay_view_global_state_controller_test, /* root= */ null);
+
+ when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
+
mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
mCarNavigationBarController, mSystemUIOverlayWindowController);
verify(mSystemUIOverlayWindowController).attach();
-
- mBaseLayout = new FrameLayout(mContext);
-
- when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
}
@Test
@@ -87,182 +100,445 @@
}
@Test
- public void showView_nothingAlreadyShown_navigationBarsHidden() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ public void showView_nothingAlreadyShown_shouldShowNavBarFalse_navigationBarsHidden() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mCarNavigationBarController).hideBars();
}
@Test
- public void showView_nothingAlreadyShown_windowIsExpanded() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ public void showView_nothingAlreadyShown_shouldShowNavBarTrue_navigationBarsShown() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void showView_nothingAlreadyShown_windowIsSetVisible() {
+ setupOverlayViewController1();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mSystemUIOverlayWindowController).setWindowVisible(true);
}
@Test
- public void showView_somethingAlreadyShown_navigationBarsHidden() {
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ public void showView_nothingAlreadyShown_newHighestZOrder() {
+ setupOverlayViewController1();
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
- verify(mCarNavigationBarController, never()).hideBars();
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController1);
}
@Test
- public void showView_somethingAlreadyShown_windowIsExpanded() {
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() {
+ setupOverlayViewController1();
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
+ OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isTrue();
+ }
+
+ @Test
+ public void showView_newHighestZOrder() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void showView_newHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void showView_newHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void showView_newHighestZOrder_correctViewsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray())
+ .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER,
+ OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
+ }
+
+ @Test
+ public void showView_oldHighestZOrder() {
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void showView_oldHighestZOrder_correctViewsShown() {
+ setupOverlayViewController1();
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray())
+ .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER,
+ OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
+ }
+
+ @Test
+ public void showView_somethingAlreadyShown_windowVisibleNotCalled() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
verify(mSystemUIOverlayWindowController, never()).setWindowVisible(true);
}
@Test
public void showView_viewControllerNotInflated_inflateViewController() {
- when(mOverlayViewController.isInflated()).thenReturn(false);
+ setupOverlayViewController2();
+ when(mOverlayViewController2.isInflated()).thenReturn(false);
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
- verify(mOverlayViewController).inflate(mBaseLayout);
+ verify(mOverlayViewController2).inflate(mBaseLayout);
}
@Test
public void showView_viewControllerInflated_inflateViewControllerNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
+ setupOverlayViewController2();
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
- verify(mOverlayViewController, never()).inflate(mBaseLayout);
+ verify(mOverlayViewController2, never()).inflate(mBaseLayout);
+ }
+
+ @Test
+ public void showView_panelViewController_inflateViewControllerNotCalled() {
+ setupOverlayPanelViewController();
+
+ mOverlayViewGlobalStateController.showView(mOverlayPanelViewController, mRunnable);
+
+ verify(mOverlayPanelViewController, never()).inflate(mBaseLayout);
+ verify(mOverlayPanelViewController, never()).isInflated();
}
@Test
public void showView_showRunnableCalled() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ setupOverlayViewController1();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mRunnable).run();
}
@Test
- public void showView_overlayViewControllerAddedToShownSet() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mShownSet.contains(
- mOverlayViewController.getClass().getName())).isTrue();
- }
-
- @Test
public void hideView_viewControllerNotInflated_hideRunnableNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(false);
+ when(mOverlayViewController2.isInflated()).thenReturn(false);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mRunnable, never()).run();
}
@Test
public void hideView_nothingShown_hideRunnableNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.clear();
+ when(mOverlayViewController2.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mZOrderMap.clear();
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mRunnable, never()).run();
}
@Test
public void hideView_viewControllerNotShown_hideRunnableNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController2.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mRunnable, never()).run();
}
@Test
public void hideView_viewControllerShown_hideRunnableCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
verify(mRunnable).run();
}
@Test
- public void hideView_viewControllerOnlyShown_nothingShown() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ public void hideView_viewControllerOnlyShown_noHighestZOrder() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
- assertThat(mOverlayViewGlobalStateController.mShownSet.isEmpty()).isTrue();
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isNull();
}
@Test
- public void hideView_viewControllerNotOnlyShown_navigationBarNotShown() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ public void hideView_viewControllerOnlyShown_nothingShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
- verify(mCarNavigationBarController, never()).showBars();
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void hideView_viewControllerOnlyShown_viewControllerNotShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
+ OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isFalse();
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_twoViewsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController1);
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_threeViewsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ setupOverlayPanelViewController();
+ setOverlayViewControllerAsShowing(mOverlayPanelViewController);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayPanelViewController, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void hideView_oldHighestZOrder() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
}
@Test
public void hideView_viewControllerNotOnlyShown_windowNotCollapsed() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mSystemUIOverlayWindowController, never()).setWindowVisible(false);
}
@Test
public void hideView_viewControllerOnlyShown_navigationBarShown() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
verify(mCarNavigationBarController).showBars();
}
@Test
public void hideView_viewControllerOnlyShown_windowCollapsed() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
verify(mSystemUIOverlayWindowController).setWindowVisible(false);
}
@Test
public void inflateView_notInflated_inflates() {
- when(mOverlayViewController.isInflated()).thenReturn(false);
+ when(mOverlayViewController2.isInflated()).thenReturn(false);
- mOverlayViewGlobalStateController.inflateView(mOverlayViewController);
+ mOverlayViewGlobalStateController.inflateView(mOverlayViewController2);
- verify(mOverlayViewController).inflate(mBaseLayout);
+ verify(mOverlayViewController2).inflate(mBaseLayout);
}
@Test
public void inflateView_alreadyInflated_doesNotInflate() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
+ when(mOverlayViewController2.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.inflateView(mOverlayViewController);
+ mOverlayViewGlobalStateController.inflateView(mOverlayViewController2);
- verify(mOverlayViewController, never()).inflate(mBaseLayout);
+ verify(mOverlayViewController2, never()).inflate(mBaseLayout);
+ }
+
+ private void setupOverlayViewController1() {
+ setupOverlayViewController(mOverlayViewController1, R.id.overlay_view_controller_stub_1,
+ R.id.overlay_view_controller_1);
+ }
+
+ private void setupOverlayViewController2() {
+ setupOverlayViewController(mOverlayViewController2, R.id.overlay_view_controller_stub_2,
+ R.id.overlay_view_controller_2);
+ }
+
+ private void setupOverlayPanelViewController() {
+ setupOverlayViewController(mOverlayPanelViewController, R.id.overlay_view_controller_stub_3,
+ R.id.overlay_view_controller_3);
+ }
+
+ private void setupOverlayViewController(OverlayViewController overlayViewController,
+ int stubId, int inflatedId) {
+ ViewStub viewStub = mBaseLayout.findViewById(stubId);
+ View layout;
+ if (viewStub == null) {
+ layout = mBaseLayout.findViewById(inflatedId);
+ } else {
+ layout = viewStub.inflate();
+ }
+ when(overlayViewController.getLayout()).thenReturn(layout);
+ when(overlayViewController.isInflated()).thenReturn(true);
+ }
+
+ private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) {
+ mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null);
+ Mockito.reset(mCarNavigationBarController, mSystemUIOverlayWindowController);
+ when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
}
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 0c70e10..8f919c3 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -275,6 +275,13 @@
return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
}
+ @Override
+ public Cursor queryChildDocumentsForManage(
+ String parentDocId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+ return queryChildDocumentsShowAll(parentDocId, projection, sortOrder);
+ }
+
/**
* Check that the directory is the root of storage or blocked file from tree.
*
diff --git a/packages/InputDevices/OWNERS b/packages/InputDevices/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/packages/InputDevices/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/packages/InputDevices/res/raw/keyboard_layout_croatian_and_slovenian.kcm b/packages/InputDevices/res/raw/keyboard_layout_croatian_and_slovenian.kcm
index eec9d27..96445a4 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_croatian_and_slovenian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_croatian_and_slovenian.kcm
@@ -258,9 +258,9 @@
}
key SEMICOLON {
- label: '\u010d'
- base: '\u010c'
- shift, capslock: '\u010d'
+ label: '\u010c'
+ base: '\u010d'
+ shift, capslock: '\u010c'
}
key APOSTROPHE {
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index 8c2fab0..44cfef0 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -57,7 +57,7 @@
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Da li želite da deinstalirate ovu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i podaci uz nje biće uklonjeni za "<b>"sve"</b>" korisnike ovog uređaja."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li da deinstalirate ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni."</string>
- <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni. Ovo utiče na sve korisnike ovog uređaja, uključujući i one sa profilima za Work."</string>
+ <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni. Ovo utiče na sve korisnike ovog uređaja, uključujući i one sa poslovnim profilima."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Aktivna deinstaliranja"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neuspela deinstaliranja"</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 30f6a21..60934b1 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -24,8 +24,8 @@
<string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> स्थापना गर्दै…"</string>
<string name="install_done" msgid="5987363587661783896">"एप स्थापना गरियो।"</string>
<string name="install_confirm_question" msgid="8176284075816604590">"तपाईं यो एप स्थापना गर्न चाहनुहुन्छ?"</string>
- <string name="install_confirm_question_update" msgid="7942235418781274635">"तपाईं यो पहिलेदेखि नै विद्यमान अनुप्रयोगको साटो यसको अद्यावधिक संस्करण स्थापना गर्न चाहनुहुन्छ? तपाईंको विद्यमान डेटा गुम्ने छैन।"</string>
- <string name="install_confirm_question_update_system" msgid="4713001702777910263">"तपाईं यो अन्तर्निर्मित अनुप्रयोगको साटो यसको अद्यावधिक संस्करण स्थापना गर्न चाहनुहुन्छ? तपाईंको विद्यमान डेटा गुम्ने छैन।"</string>
+ <string name="install_confirm_question_update" msgid="7942235418781274635">"तपाईं यो पहिलेदेखि नै विद्यमान एपको साटो यसको अद्यावधिक संस्करण स्थापना गर्न चाहनुहुन्छ? तपाईंको विद्यमान डेटा गुम्ने छैन।"</string>
+ <string name="install_confirm_question_update_system" msgid="4713001702777910263">"तपाईं यो अन्तर्निर्मित एपको साटो यसको अद्यावधिक संस्करण स्थापना गर्न चाहनुहुन्छ? तपाईंको विद्यमान डेटा गुम्ने छैन।"</string>
<string name="install_failed" msgid="5777824004474125469">"एप स्थापना गरिएन।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
@@ -49,16 +49,16 @@
<string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"अनुमति छैन"</string>
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"हालका प्रयोगकर्तालाई यो स्थापना रद्द गर्ने कार्य गर्ने अनुमति छैन।"</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"त्रुटि"</string>
- <string name="generic_error_dlg_text" msgid="5287861443265795232">"अनुप्रयोगको स्थापना रद्द गर्न सकिएन।"</string>
- <string name="uninstall_application_title" msgid="4045420072401428123">"अनुप्रयोगको स्थापना रद्द गर्नु…"</string>
+ <string name="generic_error_dlg_text" msgid="5287861443265795232">"एपको स्थापना रद्द गर्न सकिएन।"</string>
+ <string name="uninstall_application_title" msgid="4045420072401428123">"एपको स्थापना रद्द गर्नु…"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"अद्यावधिकको स्थापना रद्द गर्नु…"</string>
- <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> निम्न अनुप्रयोगको अंश हो:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"तपाईं यो अनुप्रयोगको स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
+ <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> निम्न एपको अंश हो:"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"तपाईं यो एपको स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"तपाईं "<b>"सबै"</b>" प्रयोगकर्ताका लागि यो एपको स्थापना रद्द गर्न चाहनुहुन्छ? यन्त्रका "<b>"सबै"</b>" प्रयोगकर्ताहरूबाट उक्त एप र यसको डेटा हटाइने छ।"</string>
- <string name="uninstall_application_text_user" msgid="498072714173920526">"तपाईं प्रयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> का लागि यो अनुप्रयोगको स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
- <string name="uninstall_update_text" msgid="863648314632448705">"यस अनुप्रयोगलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ।"</string>
- <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"यस अनुप्रयोगलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ। यसले यस यन्त्रका कार्य प्रोफाइल भएका लगायत सबै प्रयोगकर्ताहरूमा असर पार्छ।"</string>
- <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> अनुप्रयोगको डेटा राख्नुहोस्।"</string>
+ <string name="uninstall_application_text_user" msgid="498072714173920526">"तपाईं प्रयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> का लागि यो एपको स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
+ <string name="uninstall_update_text" msgid="863648314632448705">"यस एपलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ।"</string>
+ <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"यस एपलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ। यसले यस यन्त्रका कार्य प्रोफाइल भएका लगायत सबै प्रयोगकर्ताहरूमा असर पार्छ।"</string>
+ <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> एपको डेटा राख्नुहोस्।"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"चलिरहेका स्थापना रद्द गर्ने कार्यहरू"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"असफल भएका स्थापना रद्द गर्ने कार्यहरू"</string>
<string name="uninstalling" msgid="8709566347688966845">"स्थापना रद्द गर्दै…"</string>
@@ -67,12 +67,12 @@
<string name="uninstall_done_app" msgid="4588850984473605768">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> को स्थापना रद्द गरियो"</string>
<string name="uninstall_failed" msgid="1847750968168364332">"स्थापना रद्द गर्न सकिएन।"</string>
<string name="uninstall_failed_app" msgid="5506028705017601412">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> को स्थापना रद्द गर्ने कार्य असफल भयो।"</string>
- <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"यन्त्रको सक्रिय प्रशासकीय अनुप्रयोगको स्थापना रद्द गर्न मिल्दैन"</string>
- <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"<xliff:g id="USERNAME">%1$s</xliff:g> को यन्त्रको सक्रिय प्रशासकीय अनुप्रयोगको स्थापना रद्द गर्न मिल्दैन"</string>
- <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"अन्य प्रयोगकर्ताहरूका लागि यस अनुप्रयोगको स्थापना रद्द गरे पनि केही प्रयोगकर्ता वा प्रोफाइलहरूलाई यसको आवश्यकता पर्दछ"</string>
+ <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"यन्त्रको सक्रिय प्रशासकीय एपको स्थापना रद्द गर्न मिल्दैन"</string>
+ <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"<xliff:g id="USERNAME">%1$s</xliff:g> को यन्त्रको सक्रिय प्रशासकीय एपको स्थापना रद्द गर्न मिल्दैन"</string>
+ <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"अन्य प्रयोगकर्ताहरूका लागि यस एपको स्थापना रद्द गरे पनि केही प्रयोगकर्ता वा प्रोफाइलहरूलाई यसको आवश्यकता पर्दछ"</string>
<string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"यो एप तपाईंको प्रोफाइलका लागि आवश्यक छ र यसको स्थापना रद्द गर्न सकिँदैन।"</string>
<string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"यो एप तपाईंको यन्त्रका प्रशासकका लागि आवश्यक छ र यसको स्थापना रद्द गर्न सकिँदैन।"</string>
- <string name="manage_device_administrators" msgid="3092696419363842816">"यन्त्रका व्यवस्थापकीय अनुप्रयोगको व्यवस्थापन गर्नु…"</string>
+ <string name="manage_device_administrators" msgid="3092696419363842816">"यन्त्रका व्यवस्थापकीय एपको व्यवस्थापन गर्नु…"</string>
<string name="manage_users" msgid="1243995386982560813">"प्रयोगकर्ताहरूको व्यवस्थापन गर्नुहोस्"</string>
<string name="uninstall_failed_msg" msgid="2176744834786696012">"<xliff:g id="APP_NAME">%1$s</xliff:g> को स्थापना रद्द गर्न सकिएन।"</string>
<string name="Parse_error_dlg_text" msgid="1661404001063076789">"प्याकेजलाई पार्स गर्ने क्रममा समस्या भयो।"</string>
@@ -89,7 +89,7 @@
<string name="anonymous_source_continue" msgid="4375745439457209366">"जारी राख्नुहोस्"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"सेटिङहरू"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"वेयर एपहरूको स्थापना/स्थापना रद्द गर्दै"</string>
- <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"अनुप्रयोगको स्थापना गरिएको सूचना"</string>
+ <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"एपको स्थापना गरिएको सूचना"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"सफलतापूर्वक स्थापना गरियो"</string>
<string name="notification_installation_success_status" msgid="3172502643504323321">"“<xliff:g id="APPNAME">%1$s</xliff:g>” सफलतापूर्वक स्थापना गरियो"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index 65d1427..d539f6f6 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -22,20 +22,20 @@
<string name="cancel" msgid="1018267193425558088">"Cancelar"</string>
<string name="installing" msgid="4921993079741206516">"A instalar…"</string>
<string name="installing_app" msgid="1165095864863849422">"A instalar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
- <string name="install_done" msgid="5987363587661783896">"Aplicação instalada."</string>
- <string name="install_confirm_question" msgid="8176284075816604590">"Pretende instalar esta aplicação?"</string>
- <string name="install_confirm_question_update" msgid="7942235418781274635">"Pretende instalar uma atualização para esta aplicação existente? Os seus dados existentes não serão perdidos."</string>
- <string name="install_confirm_question_update_system" msgid="4713001702777910263">"Pretende instalar uma atualização para esta aplicação incorporada? Os seus dados existentes não serão perdidos."</string>
+ <string name="install_done" msgid="5987363587661783896">"App instalada."</string>
+ <string name="install_confirm_question" msgid="8176284075816604590">"Pretende instalar esta app?"</string>
+ <string name="install_confirm_question_update" msgid="7942235418781274635">"Pretende instalar uma atualização para esta app existente? Os seus dados existentes não serão perdidos."</string>
+ <string name="install_confirm_question_update_system" msgid="4713001702777910263">"Pretende instalar uma atualização para esta app incorporada? Os seus dados existentes não serão perdidos."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicação não instalada."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Foi bloqueada a instalação do pacote."</string>
- <string name="install_failed_conflict" msgid="3493184212162521426">"A aplicação não foi instalada porque o pacote entra em conflito com um pacote existente."</string>
- <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"A aplicação não foi instalada porque não é compatível com o seu tablet."</string>
- <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"Esta aplicação não é compatível com a sua TV."</string>
- <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"A aplicação não foi instalada porque não é compatível com o seu telemóvel."</string>
- <string name="install_failed_invalid_apk" msgid="8581007676422623930">"A aplicação não foi instalada porque o pacote parece ser inválido."</string>
- <string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"Não foi possível instalar a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> no tablet."</string>
- <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"Não foi possível instalar a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> na TV."</string>
- <string name="install_failed_msg" product="default" msgid="6484461562647915707">"Não foi possível instalar a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> no telemóvel."</string>
+ <string name="install_failed_conflict" msgid="3493184212162521426">"A app não foi instalada porque o pacote entra em conflito com um pacote existente."</string>
+ <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"A app não foi instalada porque não é compatível com o seu tablet."</string>
+ <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"Esta app não é compatível com a sua TV."</string>
+ <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"A app não foi instalada porque não é compatível com o seu telemóvel."</string>
+ <string name="install_failed_invalid_apk" msgid="8581007676422623930">"A app não foi instalada porque o pacote parece ser inválido."</string>
+ <string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"Não foi possível instalar a app <xliff:g id="APP_NAME">%1$s</xliff:g> no tablet."</string>
+ <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"Não foi possível instalar a app <xliff:g id="APP_NAME">%1$s</xliff:g> na TV."</string>
+ <string name="install_failed_msg" product="default" msgid="6484461562647915707">"Não foi possível instalar a app <xliff:g id="APP_NAME">%1$s</xliff:g> no telemóvel."</string>
<string name="launch" msgid="3952550563999890101">"Abrir"</string>
<string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"O administrador não permite a instalação de aplicações obtidas de fontes desconhecidas."</string>
<string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este utilizador não pode instalar aplicações desconhecidas."</string>
@@ -43,53 +43,53 @@
<string name="ok" msgid="7871959885003339302">"OK"</string>
<string name="manage_applications" msgid="5400164782453975580">"Gerir app"</string>
<string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sem espaço"</string>
- <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Não foi possível instalar a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>. Liberte algum espaço e tente novamente."</string>
+ <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Não foi possível instalar a app <xliff:g id="APP_NAME">%1$s</xliff:g>. Liberte algum espaço e tente novamente."</string>
<string name="app_not_found_dlg_title" msgid="5107924008597470285">"Aplicação não encontrada"</string>
- <string name="app_not_found_dlg_text" msgid="5219983779377811611">"A aplicação não foi encontrada na lista de aplicações instaladas."</string>
+ <string name="app_not_found_dlg_text" msgid="5219983779377811611">"A app não foi encontrada na lista de aplicações instaladas."</string>
<string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Não permitido."</string>
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"O utilizador atual não tem autorização para efetuar esta desinstalação."</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"Erro"</string>
- <string name="generic_error_dlg_text" msgid="5287861443265795232">"Não foi possível desinstalar a aplicação."</string>
- <string name="uninstall_application_title" msgid="4045420072401428123">"Desinstalar aplicação"</string>
+ <string name="generic_error_dlg_text" msgid="5287861443265795232">"Não foi possível desinstalar a app."</string>
+ <string name="uninstall_application_title" msgid="4045420072401428123">"Desinstalar app"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string>
- <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> faz parte da seguinte aplicação:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Pretende desinstalar esta aplicação?"</string>
- <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Pretende desinstalar esta aplicação para "<b>"todos"</b>" os utilizadores? A aplicação e os respetivos dados serão removidos de "<b>"todos"</b>" os utilizadores do dispositivo."</string>
- <string name="uninstall_application_text_user" msgid="498072714173920526">"Pretende desinstalar esta aplicação para o utilizador <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
- <string name="uninstall_update_text" msgid="863648314632448705">"Pretende substituir esta aplicação pela versão de fábrica? Todos os dados são removidos."</string>
- <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Pretende substituir esta aplicação pela versão de fábrica? Todos os dados são removidos. Esta ação afeta todos os utilizadores deste dispositivo, incluindo os que têm perfis de trabalho."</string>
- <string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados da aplicação."</string>
+ <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> faz parte da seguinte app:"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Pretende desinstalar esta app?"</string>
+ <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Pretende desinstalar esta app para "<b>"todos"</b>" os utilizadores? A app e os respetivos dados serão removidos de "<b>"todos"</b>" os utilizadores do dispositivo."</string>
+ <string name="uninstall_application_text_user" msgid="498072714173920526">"Pretende desinstalar esta app para o utilizador <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_update_text" msgid="863648314632448705">"Pretende substituir esta app pela versão de fábrica? Todos os dados são removidos."</string>
+ <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Pretende substituir esta app pela versão de fábrica? Todos os dados são removidos. Esta ação afeta todos os utilizadores deste dispositivo, incluindo os que têm perfis de trabalho."</string>
+ <string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados da app."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalações em execução"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalações com falha"</string>
<string name="uninstalling" msgid="8709566347688966845">"A desinstalar…"</string>
- <string name="uninstalling_app" msgid="8866082646836981397">"A desinstalar a aplicação <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
+ <string name="uninstalling_app" msgid="8866082646836981397">"A desinstalar a app <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
<string name="uninstall_done" msgid="439354138387969269">"Desinstalação concluída."</string>
- <string name="uninstall_done_app" msgid="4588850984473605768">"A aplicação <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> foi desinstalada"</string>
+ <string name="uninstall_done_app" msgid="4588850984473605768">"A app <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> foi desinstalada"</string>
<string name="uninstall_failed" msgid="1847750968168364332">"Desinstalação sem êxito."</string>
- <string name="uninstall_failed_app" msgid="5506028705017601412">"Falha ao desinstalar a aplicação <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
- <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"Não é possível desinstalar a aplicação de administração de dispositivos ativa."</string>
- <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"Não é possível desinstalar a aplicação de administração de dispositivos ativa para <xliff:g id="USERNAME">%1$s</xliff:g>."</string>
- <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"Esta aplicação é necessária para alguns utilizadores ou perfis e foi desinstalada para outros."</string>
- <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"O perfil necessita desta aplicação e não é possível desinstalá-la."</string>
+ <string name="uninstall_failed_app" msgid="5506028705017601412">"Falha ao desinstalar a app <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"Não é possível desinstalar a app de administração de dispositivos ativa."</string>
+ <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"Não é possível desinstalar a app de administração de dispositivos ativa para <xliff:g id="USERNAME">%1$s</xliff:g>."</string>
+ <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"Esta app é necessária para alguns utilizadores ou perfis e foi desinstalada para outros."</string>
+ <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"O perfil necessita desta app e não é possível desinstalá-la."</string>
<string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"Esta app é exigida pelo administrador do disp. e não pode ser desinstalada."</string>
<string name="manage_device_administrators" msgid="3092696419363842816">"Gerir aplicações de administração de dispositivos"</string>
<string name="manage_users" msgid="1243995386982560813">"Gerir utilizadores"</string>
- <string name="uninstall_failed_msg" msgid="2176744834786696012">"Não foi possível desinstalar a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="uninstall_failed_msg" msgid="2176744834786696012">"Não foi possível desinstalar a app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="Parse_error_dlg_text" msgid="1661404001063076789">"Ocorreu um problema ao analisar o pacote."</string>
<string name="wear_not_allowed_dlg_title" msgid="8664785993465117517">"Android Wear"</string>
<string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
- <string name="message_staging" msgid="8032722385658438567">"A preparar a aplicação…"</string>
+ <string name="message_staging" msgid="8032722385658438567">"A preparar a app…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Desconhecida"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"Para sua segurança, o tablet não está autorizado a instalar aplicações desconhecidas a partir desta fonte."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"Para sua segurança, a TV não está autorizada a instalar aplicações desconhecidas a partir desta fonte."</string>
<string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"Para sua segurança, o telemóvel não está autorizado a instalar aplicações desconhecidas a partir desta fonte."</string>
- <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"O seu telemóvel e os dados pessoais estão mais vulneráveis a ataques por parte de aplicações desconhecidas. Ao instalar esta aplicação, concorda que é responsável por quaisquer danos causados ao telemóvel ou pelas perdas de dados que possam resultar da utilização da mesma."</string>
- <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"O seu tablet e os dados pessoais estão mais vulneráveis a ataques por parte de aplicações desconhecidas. Ao instalar esta aplicação, concorda que é responsável por quaisquer danos causados ao tablet ou pelas perdas de dados que possam resultar da utilização da mesma."</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"A sua TV e os dados pessoais estão mais vulneráveis a ataques por parte de aplicações desconhecidas. Ao instalar esta aplicação, concorda que é responsável por quaisquer danos causados à TV ou pelas perdas de dados que possam resultar da utilização da mesma."</string>
+ <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"O seu telemóvel e os dados pessoais estão mais vulneráveis a ataques por parte de aplicações desconhecidas. Ao instalar esta app, concorda que é responsável por quaisquer danos causados ao telemóvel ou pelas perdas de dados que possam resultar da utilização da mesma."</string>
+ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"O seu tablet e os dados pessoais estão mais vulneráveis a ataques por parte de aplicações desconhecidas. Ao instalar esta app, concorda que é responsável por quaisquer danos causados ao tablet ou pelas perdas de dados que possam resultar da utilização da mesma."</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"A sua TV e os dados pessoais estão mais vulneráveis a ataques por parte de aplicações desconhecidas. Ao instalar esta app, concorda que é responsável por quaisquer danos causados à TV ou pelas perdas de dados que possam resultar da utilização da mesma."</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"Definições"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Instalar/desinstalar aplicações Wear"</string>
- <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notificação de aplicação instalada"</string>
- <string name="notification_installation_success_message" msgid="6450467996056038442">"Aplicação instalada com êxito"</string>
+ <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notificação de app instalada"</string>
+ <string name="notification_installation_success_message" msgid="6450467996056038442">"App instalada com êxito"</string>
<string name="notification_installation_success_status" msgid="3172502643504323321">"Aplicação \"<xliff:g id="APPNAME">%1$s</xliff:g>\" instalada com êxito"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index 51995a3..2746284 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -57,7 +57,7 @@
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Да ли желите да деинсталирате ову апликацију за "<b>"све"</b>" кориснике? Апликација и подаци уз ње биће уклоњени за "<b>"све"</b>" кориснике овог уређаја."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Желите ли да деинсталирате ову апликацију за корисника <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени."</string>
- <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени. Ово утиче на све кориснике овог уређаја, укључујући и оне са профилима за Work."</string>
+ <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени. Ово утиче на све кориснике овог уређаја, укључујући и оне са пословним профилима."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> података апликације."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Активна деинсталирања"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Неуспела деинсталирања"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index a95677d..5675c99 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -38,8 +38,6 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
@@ -526,18 +524,16 @@
case ContentResolver.SCHEME_FILE: {
File sourceFile = new File(packageUri.getPath());
- PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile);
+ mPkgInfo = PackageUtil.getPackageInfo(this, sourceFile,
+ PackageManager.GET_PERMISSIONS);
// Check for parse errors
- if (parsed == null) {
+ if (mPkgInfo == null) {
Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return false;
}
- mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
- PackageManager.GET_PERMISSIONS, 0, 0, null,
- new PackageUserState());
mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
} break;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index 0e89f56..d3a9f8f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -22,9 +22,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -53,12 +52,12 @@
/**
* Utility method to get package information for a given {@link File}
*/
- public static PackageParser.Package getPackageInfo(Context context, File sourceFile) {
- final PackageParser parser = new PackageParser();
- parser.setCallback(new PackageParser.CallbackImpl(context.getPackageManager()));
+ @Nullable
+ public static PackageInfo getPackageInfo(Context context, File sourceFile, int flags) {
try {
- return parser.parsePackage(sourceFile, 0);
- } catch (PackageParserException e) {
+ return context.getPackageManager().getPackageArchiveInfo(sourceFile.getAbsolutePath(),
+ flags);
+ } catch (Exception ignored) {
return null;
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
index e5f7613..06b1c16 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
@@ -22,11 +22,11 @@
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
@@ -49,6 +49,7 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -244,47 +245,50 @@
Log.e(TAG, "Could not create a temp file from FD for " + packageName);
return;
}
- PackageParser.Package pkg = PackageUtil.getPackageInfo(this, tempFile);
- if (pkg == null) {
+ PackageInfo pkgInfo = PackageUtil.getPackageInfo(this, tempFile,
+ PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS);
+ if (pkgInfo == null) {
Log.e(TAG, "Could not parse apk information for " + packageName);
return;
}
- if (!pkg.packageName.equals(packageName)) {
+ if (!pkgInfo.packageName.equals(packageName)) {
Log.e(TAG, "Wearable Package Name has to match what is provided for " +
packageName);
return;
}
- pkg.applicationInfo.sourceDir = tempFile.getPath();
- pkg.applicationInfo.publicSourceDir = tempFile.getPath();
+ ApplicationInfo appInfo = pkgInfo.applicationInfo;
+ appInfo.sourceDir = tempFile.getPath();
+ appInfo.publicSourceDir = tempFile.getPath();
getLabelAndUpdateNotification(packageName,
- getString(R.string.installing_app, pkg.applicationInfo.loadLabel(pm)));
+ getString(R.string.installing_app, appInfo.loadLabel(pm)));
- List<String> wearablePerms = pkg.requestedPermissions;
+ List<String> wearablePerms = Arrays.asList(pkgInfo.requestedPermissions);
// Log if the installed pkg has a higher version number.
if (existingPkgInfo != null) {
- if (existingPkgInfo.getLongVersionCode() == pkg.getLongVersionCode()) {
+ long longVersionCode = pkgInfo.getLongVersionCode();
+ if (existingPkgInfo.getLongVersionCode() == longVersionCode) {
if (skipIfSameVersion) {
- Log.w(TAG, "Version number (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number (" + longVersionCode +
") of new app is equal to existing app for " + packageName +
"; not installing due to versionCheck");
return;
} else {
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is equal to existing app for " + packageName);
}
- } else if (existingPkgInfo.getLongVersionCode() > pkg.getLongVersionCode()) {
+ } else if (existingPkgInfo.getLongVersionCode() > longVersionCode) {
if (skipIfLowerVersion) {
// Starting in Feldspar, we are not going to allow downgrades of any app.
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is lower than existing app ( "
+ existingPkgInfo.getLongVersionCode() +
") for " + packageName + "; not installing due to versionCheck");
return;
} else {
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is lower than existing app ( "
+ existingPkgInfo.getLongVersionCode() + ") for " + packageName);
}
@@ -309,14 +313,12 @@
// Check that the wearable has all the features.
boolean hasAllFeatures = true;
- if (pkg.reqFeatures != null) {
- for (FeatureInfo feature : pkg.reqFeatures) {
- if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
- (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
- Log.e(TAG, "Wearable does not have required feature: " + feature +
- " for " + packageName);
- hasAllFeatures = false;
- }
+ for (FeatureInfo feature : pkgInfo.reqFeatures) {
+ if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
+ (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
+ Log.e(TAG, "Wearable does not have required feature: " + feature +
+ " for " + packageName);
+ hasAllFeatures = false;
}
}
@@ -328,8 +330,8 @@
// wearable package.
// If the app is targeting API level 23, we will also start a service in ClockworkHome
// which will ultimately prompt the user to accept/reject permissions.
- if (checkPerms && !checkPermissions(pkg, companionSdkVersion, companionDeviceVersion,
- permUri, wearablePerms, tempFile)) {
+ if (checkPerms && !checkPermissions(pkgInfo, companionSdkVersion,
+ companionDeviceVersion, permUri, wearablePerms, tempFile)) {
Log.w(TAG, "Wearable does not have enough permissions.");
return;
}
@@ -382,7 +384,7 @@
}
}
- private boolean checkPermissions(PackageParser.Package pkg, int companionSdkVersion,
+ private boolean checkPermissions(PackageInfo pkgInfo, int companionSdkVersion,
int companionDeviceVersion, Uri permUri, List<String> wearablePermissions,
File apkFile) {
// Assumption: We are running on Android O.
@@ -390,12 +392,12 @@
// app. If the Wear App is then not targeting M, there may be permissions that are not
// granted on the Phone app (by the user) right now and we cannot just grant it for the Wear
// app.
- if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+ if (pkgInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
// Install the app if Wear App is ready for the new perms model.
return true;
}
- if (!doesWearHaveUngrantedPerms(pkg.packageName, permUri, wearablePermissions)) {
+ if (!doesWearHaveUngrantedPerms(pkgInfo.packageName, permUri, wearablePermissions)) {
// All permissions requested by the watch are already granted on the phone, no need
// to do anything.
return true;
diff --git a/packages/PrintSpooler/res/values-kn/strings.xml b/packages/PrintSpooler/res/values-kn/strings.xml
index 868320d..150ede4 100644
--- a/packages/PrintSpooler/res/values-kn/strings.xml
+++ b/packages/PrintSpooler/res/values-kn/strings.xml
@@ -104,7 +104,7 @@
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"ಫೈಲ್ಗೆ ರೈಟ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"ಕ್ಷಮಿಸಿ, ಅದು ಕೆಲಸ ಮಾಡುತ್ತಿಲ್ಲ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="print_error_retry" msgid="1426421728784259538">"ಮರುಪ್ರಯತ್ನಿಸು"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"ಮರುಪ್ರಯತ್ನಿಸಿ"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ಈ ಪ್ರಿಂಟರ್ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="print_cannot_load_page" msgid="6179560924492912009">"ಪೂರ್ವವೀಕ್ಷಣೆ ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"ಪೂರ್ವವೀಕ್ಷಣೆ ತಯಾರಾಗುತ್ತಿದೆ…"</string>
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index 86c5351..a1675fa 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -94,7 +94,7 @@
<item msgid="2762241247228983754">"ରଙ୍ଗ"</item>
</string-array>
<string-array name="duplex_mode_labels">
- <item msgid="3882302912790928315">"କିଛିନୁହେଁ"</item>
+ <item msgid="3882302912790928315">"କିଛି ନାହିଁ"</item>
<item msgid="7296563835355641719">"ଲମ୍ବା ପ୍ରାନ୍ତ"</item>
<item msgid="79513688117503758">"ଛୋଟ ପ୍ରାନ୍ତ"</item>
</string-array>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 1c128b4..4517efe 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -33,7 +33,7 @@
<string name="pages_range_example" msgid="8558694453556945172">"p. ex. 1-5, 8, 11-13"</string>
<string name="print_preview" msgid="8010217796057763343">"Pré-visualização de impressão"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"Instalar o leitor de PDF para pré-visualização"</string>
- <string name="printing_app_crashed" msgid="854477616686566398">"A aplicação de impressão bloqueou"</string>
+ <string name="printing_app_crashed" msgid="854477616686566398">"A app de impressão bloqueou"</string>
<string name="generating_print_job" msgid="3119608742651698916">"A gerar tarefa de impressão"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"Guardar como PDF"</string>
<string name="all_printers" msgid="5018829726861876202">"Todas as impressoras..."</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 1709506..467a60e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -231,11 +231,6 @@
// Add the new printers, i.e. what is left.
printers.addAll(discoveredPrinters.values());
- // Do nothing if the printer list is not changed.
- if (Objects.equals(mPrinters, printers)) {
- return;
- }
-
// Update the list of printers.
mPrinters.clear();
mPrinters.addAll(printers);
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
index aaf9116..9c39f98 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="enabled_by_admin" msgid="6630472777476410137">"فعالشده توسط سرپرست"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"غیرفعالشده توسط سرپرست"</string>
+ <string name="enabled_by_admin" msgid="6630472777476410137">"توسط سرپرست فعال شده"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"توسط سرپرست غیرفعال شده"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
index 1d23c31..4ce6460 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"ଆଡମିନଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"ଆଡମିନଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
index 2da347c..8f17dc5 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="enabled_by_admin" msgid="6630472777476410137">"నిర్వాహకులు ప్రారంభించారు"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"నిర్వాహకులు నిలిపివేసారు"</string>
+ <string name="enabled_by_admin" msgid="6630472777476410137">"అడ్మిన్ ఎనేబుల్ చేశారు"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"అడ్మిన్ డిజేబుల్ చేశారు"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
index f664bb4..2c37652 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"Do quản trị viên bật"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"Bị quản trị viên tắt"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"Đã bị quản trị viên vô hiệu hóa"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index c16949a..1729027 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Toestelverstek"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Gedeaktiveer"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4c6c7b8..fad7a82 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"የመሣሪያ ነባሪ"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ተሰናክሏል"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 38b7179..b3cc832 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -235,7 +235,7 @@
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"يُرجى الاتصال بشبكة Wi-Fi."</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb، تصحيح الأخطاء، مطور برامج"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"اختصار تقرير الأخطاء"</string>
- <string name="bugreport_in_power_summary" msgid="1885529649381831775">"عرض زر في قائمة خيارات التشغيل لإعداد تقرير بالأخطاء"</string>
+ <string name="bugreport_in_power_summary" msgid="1885529649381831775">"عرض زر في قائمة زر التشغيل لإعداد تقرير بالأخطاء"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"البقاء في الوضع النشط"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"لا يتم مطلقًا دخول الشاشة في وضع السكون أثناء الشحن"</string>
<string name="bt_hci_snoop_log" msgid="7291287955649081448">"تفعيل سجلّ تطفل بواجهة وحدة تحكم المضيف في بلوتوث"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"لتقليل استنفاد البطارية وتحسين أداء الشبكة."</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"عند تفعيل هذا الوضع، قد يتم تغيير عنوان MAC لهذا الجهاز في كل مرة تتصل فيها بشبكة تم تفعيل التوزيع العشوائي لعناوين MAC عليها."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"تفرض تكلفة استخدام"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"بدون قياس"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"أحجام ذاكرة التخزين المؤقت للتسجيل"</string>
@@ -389,7 +388,7 @@
<string name="loading_injected_setting_summary" msgid="8394446285689070348">"جارٍ التحميل…"</string>
<string-array name="color_mode_names">
<item msgid="3836559907767149216">"نابض بالحياة (تلقائي)"</item>
- <item msgid="9112200311983078311">"طبيعي"</item>
+ <item msgid="9112200311983078311">"طبيعية"</item>
<item msgid="6564241960833766170">"عادي"</item>
</string-array>
<string-array name="color_mode_descriptions">
@@ -429,10 +428,10 @@
<string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا، بناءً على استخدامك (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<!-- no translation found for power_remaining_duration_only_short (7438846066602840588) -->
<skip />
- <string name="power_discharge_by_enhanced" msgid="563438403581662942">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> حسب استخدامك (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string>
- <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> حسب استخدامك."</string>
- <string name="power_discharge_by" msgid="4113180890060388350">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string>
- <string name="power_discharge_by_only" msgid="92545648425937000">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g>."</string>
+ <string name="power_discharge_by_enhanced" msgid="563438403581662942">"يُفترض أن تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> حسب استخدامك (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string>
+ <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"يُفترض أن تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> حسب استخدامك."</string>
+ <string name="power_discharge_by" msgid="4113180890060388350">"يُفترض أن تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string>
+ <string name="power_discharge_by_only" msgid="92545648425937000">"يُفترض أن تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g>."</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"حتى <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"قد ينفد شحن البطارية قبل <xliff:g id="TIME">%1$s</xliff:g>."</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"سيبقى شحن البطارية أقل من <xliff:g id="THRESHOLD">%1$s</xliff:g>."</string>
@@ -554,4 +553,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ضيف"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"الإعداد التلقائي للجهاز"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غير مفعّل"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index ef36490..ad344c3 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -549,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 62bb248..ab7ea8c 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -458,7 +458,7 @@
<string name="disabled" msgid="8017887509554714950">"Deaktiv"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"İcazə verilib"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"İcazə verilməyib"</string>
- <string name="install_other_apps" msgid="3232595082023199454">"Naməlum tətbiqlərin quraşdırılması"</string>
+ <string name="install_other_apps" msgid="3232595082023199454">"Tanınmayan tətbiqlərin quraşdırılması"</string>
<string name="home" msgid="973834627243661438">"Ayarların əsas səhifəsi"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cihaz defoltu"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 40432f8..da47bf2 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -143,11 +143,11 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Uklonjene aplikacije"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Uklonjene aplikacije i korisnici"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Ažuriranja sistema"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB Internet povezivanje"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB privezivanje"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Prenosni hotspot"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth privezivanje"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Povezivanje sa internetom"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Povezivanje i prenosni hotspot"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Privezivanje"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Privezivanje i prenosni hotspot"</string>
<string name="managed_user_title" msgid="449081789742645723">"Sve radne aplikacije"</string>
<string name="user_guest" msgid="6939192779649870792">"Gost"</string>
<string name="unknown" msgid="3544487229740637809">"Nepoznato"</string>
@@ -550,4 +550,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Podrazumevano za uređaj"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 3e2bbfe..2761d47 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"Невядома"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Карыстальнiк: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Усталяваны некаторыя стандартныя налады"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"Параметры па змаўчанні не ўсталяваныя"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"Стандартныя налады не зададзены"</string>
<string name="tts_settings" msgid="8130616705989351312">"Налады Text-to-speech"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Сінтэз маўлення"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Хуткасць маўлення"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Паказаць опцыі сертыфікацыі бесправаднога экрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Пры выбары сеткі Wi-Fi указваць у журнале RSSI для кожнага SSID"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зніжае расход зараду акумулятара і павышае прадукцыйнасць мабільных сетак"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Калі ўключаны гэты рэжым, MAC-адрас гэтай прылады можа змяняцца падчас кожнага падключэння да сеткі з актыўнай рандамізацыяй MAC-адрасоў."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Сетка з улікам трафіка"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Сетка без уліку трафіка"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Памеры буфера журнала"</string>
@@ -552,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Госць"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандартная прылада"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Выключана"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 19ad534..8150710 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандартна настройка за у-вото"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Деактивирано"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> за работа"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 94e1f23..7bae6ee 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"অজানা"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ব্যবহারকারী: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"কিছু ডিফল্ট সেট করা রয়েছে"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"কোনো ডিফল্ট সেট করা নেই"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"কোনও ডিফল্ট সেট করা নেই"</string>
<string name="tts_settings" msgid="8130616705989351312">"পাঠ্য থেকে ভাষ্য আউটপুট সেটিংস"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"টেক্সট-টু-স্পিচ"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"কথা বলার হার"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ব্যাটারির খরচ কমায় এবং নেটওয়ার্কের পারফর্ম্যান্স উন্নত করে"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"এই মোডটি চালু থাকার সময়, MAC র্যান্ডমাইজেশন চালু হওয়া এমন কোনও নেটওয়ার্কে কানেক্ট করার সময় এই ডিভাইসের MAC অ্যাড্রেস পরিবর্তিত হতে পারে।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"মিটার্ড"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"পরিমাপ করা নয়"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"লগার বাফারের আকারগুলি"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 4ef8871..fe7f8c1 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -550,4 +550,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Zadana postavka uređaja"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> za posao"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index baee151..7dad950 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra les opcions per a la certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Augmenta nivell de registre Wi‑Fi, mostra\'l per SSID RSSI al selector de Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Redueix el consum de bateria i millora el rendiment de la xarxa"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quan aquest mode està activat, és possible que l’adreça MAC d’aquest dispositiu canviï cada vegada que es connecti a una xarxa amb l\'aleatorització d\'adreces MAC activada."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"D\'ús mesurat"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"D\'ús no mesurat"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la mem. intermèdia del registrador"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Opció predeter. del dispositiu"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivat"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 26fb72ea..51548f5 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Snižuje vyčerpávání baterie a vylepšuje výkon sítě"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Když je tento režim aktivován, adresa MAC tohoto zařízení se může změnit pokaždé, když se zařízení připojí k síti s aktivovanou randomizací adres MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Měřená"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neměřená"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávací paměť protokol. nástroje"</string>
@@ -434,7 +433,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"Vydrží asi do <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"Vydrží asi do <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Baterie se může vybít do <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Baterie se může vybít kolem <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Zbývá více než <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -552,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Host"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Výchozí nastavení zařízení"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuto"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 9ab80da..88f8e92 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -211,10 +211,10 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Fejl"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Trådløs fejlretning"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Du kan se og bruge tilgængelige enheder ved at aktivere trådløs fejlretning"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Dan par med en enhed ved hjælp af en QR-kode"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Dan par med nye enheder ved hjælp af QR-kodescanneren"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Dan par med en enhed ved hjælp af en parringskode"</string>
- <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Dan par med nye enheder ved hjælp af den sekscifrede kode"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Par enhed ved hjælp af en QR-kode"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Par nye enheder ved hjælp af QR-kodescanneren"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Par enhed ved hjælp af en parringskode"</string>
+ <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Par nye enheder ved hjælp af den sekscifrede kode"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Parrede enheder"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Forbundet lige nu"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Enhedsoplysninger"</string>
@@ -222,16 +222,16 @@
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Fingeraftryk for enhed: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Forbindelsen mislykkedes"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Sørg for, at <xliff:g id="DEVICE_NAME">%1$s</xliff:g> har forbindelse til det rigtige netværk."</string>
- <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Dan par med enhed"</string>
+ <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Par med enhed"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Parringskode til Wi-Fi"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Parringen mislykkedes"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Pardannelse mislykkedes"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sørg for, at enheden er forbundet til det samme netværk."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Dan par med en enhed via Wi-Fi ved at scanne en QR-kode"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Par en enhed via Wi-Fi ved at scanne en QR-kode"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Parrer enhed…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Enheden blev ikke parret. Det skyldes enten, at QR-koden var forkert, eller at enheden ikke er forbundet til det samme netværk."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR-kode"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Dan par med en enhed via Wi-Fi ved at scanne en QR-kode"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Par en enhed via Wi-Fi ved at scanne en QR-kode"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Opret forbindelse til et Wi-Fi-netværk"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, fejlfinding, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Genvej til fejlrapportering"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæsten"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Enhedens standardindstilling"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiveret"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at denne enhed bliver anvendt. Genstart nu, eller annuller."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 73a6245..edd1580 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"WLAN-Protokollierungsebene erhöhen, pro SSID RSSI in WiFi Picker anzeigen"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wenn dieser Modus aktiviert ist, kann sich die MAC-Adresse dieses Geräts bei jeder Verbindung mit einem Netzwerk ändern, bei dem die MAC-Adressen randomisiert werden."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Kostenpflichtig"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Kostenlos"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger-Puffergrößen"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gerätestandard"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiviert"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index ceabc74..c5c0e07 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -143,9 +143,9 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Εφαρμογές που καταργήθηκαν"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Εφαρμογές και χρήστες που έχουν καταργηθεί"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Ενημερώσεις συστήματος"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"Πρόσδεση USB"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"Σύνδεση με USB"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Φορητό σημείο πρόσβασης"</string>
- <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Πρόσδεση Bluetooth"</string>
+ <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Σύνδεση με Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Πρόσδεση"</string>
<string name="tether_settings_title_all" msgid="8910259483383010470">"Πρόσ. και φορητό σημ. πρόσβ."</string>
<string name="managed_user_title" msgid="449081789742645723">"Όλες οι εφαρμ. εργασίας"</string>
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Προεπιλογή συσκευής"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ανενεργή"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Εργασία <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index fca1c50..a1c8b04 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index fca1c50..a1c8b04 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index fca1c50..a1c8b04 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index fca1c50..a1c8b04 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 95bc936..38ac8f1 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index e2d488c..c6d0d56 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -223,8 +223,8 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Error de conexión"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Asegúrate de que <xliff:g id="DEVICE_NAME">%1$s</xliff:g> esté conectado a la red correcta."</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Vincular con dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de sincroniz. de Wi‑Fi"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Error de sincronización"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de vinculación de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Error de vinculación"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Asegúrate de que el dispositivo esté conectado a la misma red."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Escanea un código QR para vincular el dispositivo mediante Wi‑Fi"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Vinculando dispositivo…"</string>
@@ -285,7 +285,7 @@
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de la red"</string>
<string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
- <string name="wifi_metered_label" msgid="8737187690304098638">"Con uso medido"</string>
+ <string name="wifi_metered_label" msgid="8737187690304098638">"De uso medido"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Sin tarifa plana"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de búfer de Logger"</string>
<string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Selecciona el tamaño del Logger por búfer"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predeterminado del dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e7d53f6..55b5cab 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -223,9 +223,9 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"No se ha podido conectar"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Comprueba que has conectado <xliff:g id="DEVICE_NAME">%1$s</xliff:g> a la red correcta"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Vincular con dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de sincronización de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de vinculación de Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"No se ha podido vincular"</string>
- <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Comprueba que el dispositivo está conectado a la misma red."</string>
+ <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Asegúrate de que el dispositivo esté conectado a la misma red."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Vincula un dispositivo mediante Wi‑Fi con un código QR"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Vinculando dispositivo…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"No se ha podido vincular el dispositivo. El código QR no era correcto o el dispositivo no estaba conectado a la misma red."</string>
@@ -234,7 +234,7 @@
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Vincula un dispositivo mediante Wi‑Fi escaneando un código QR"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conéctate a una red Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depuración, desarrollo"</string>
- <string name="bugreport_in_power" msgid="8664089072534638709">"Atajo a informe de errores"</string>
+ <string name="bugreport_in_power" msgid="8664089072534638709">"Acceso directo a informe de errores"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"Mostrar un botón en el menú de encendido para crear un informe de errores"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"Pantalla siempre encendida al cargar"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"La pantalla nunca entra en modo de suspensión si el dispositivo se está cargando"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predeterm. en el dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reiniciar ahora o cancelar."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index f6d2c01..5a11590 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Seadme vaikeseade"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Keelatud"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 685facb..1aed7e8 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Erakutsi hari gabe bistaratzeko ziurtagiriaren aukerak"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautatzailean."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Bateria gutxiago kontsumituko da, eta sarearen errendimendua hobetuko."</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Modu hau gaituta dagoenean, baliteke gailuaren MAC helbidea aldatzea MAC helbideak ausaz antolatzeko aukera gaituta daukan sare batera konektatzen den bakoitzean."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sare neurtua"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neurtu gabeko sarea"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Erregistroen buffer-tamainak"</string>
@@ -550,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gailuaren balio lehenetsia"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desgaituta"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Laneko <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index a893c75..a46d8cd 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"ناشناس"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"کاربر: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"بعضی پیشفرضها تنظیم شدهاند"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"هیچ پیشفرضی تنظیم نشده است"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"پیشفرضی تنظیم نشده است"</string>
<string name="tts_settings" msgid="8130616705989351312">"تنظیمات متن به گفتار"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"خروجی تبدیل متن به گفتار"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"سرعت گفتار"</string>
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"انتخاب نمایه"</string>
<string name="category_personal" msgid="6236798763159385225">"شخصی"</string>
- <string name="category_work" msgid="4014193632325996115">"محل کار"</string>
+ <string name="category_work" msgid="4014193632325996115">"کاری"</string>
<string name="development_settings_title" msgid="140296922921597393">"گزینههای برنامهنویسان"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"فعال کردن گزینههای برنامهنویس"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"تنظیم گزینههای مربوط به طراحی برنامه"</string>
@@ -253,7 +253,7 @@
<string name="wifi_scan_throttling" msgid="2985624788509913617">"محدود کردن اسکن کردن Wi‑Fi"</string>
<string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"تصادفیسازی MAC بهبودیافته برای Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"داده تلفن همراه همیشه فعال باشد"</string>
- <string name="tethering_hardware_offload" msgid="4116053719006939161">"شتاب سختافزاری اتصال به اینترنت با تلفن همراه"</string>
+ <string name="tethering_hardware_offload" msgid="4116053719006939161">"شتاب سختافزاری اشتراکگذاری اینترنت"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاههای بلوتوث بدون نام"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"غیرفعال کردن میزان صدای مطلق"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"فعال کردن Gabeldorsche"</string>
@@ -486,7 +486,7 @@
<string name="ims_reg_status_registered" msgid="884916398194885457">"ثبتشده"</string>
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ثبت نشده است"</string>
<string name="status_unavailable" msgid="5279036186589861608">"در دسترس نیست"</string>
- <string name="wifi_status_mac_randomized" msgid="466382542497832189">"ویژگی تصادفیسازی MAC فعال است"</string>
+ <string name="wifi_status_mac_randomized" msgid="466382542497832189">"ویژگی MAC تصادفی است"</string>
<plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
<item quantity="one">%1$d دستگاه متصل</item>
<item quantity="other">%1$d دستگاه متصل</item>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string>
<string name="guest_nickname" msgid="6332276931583337261">"مهمان"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"پیشفرض دستگاه"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیرفعال"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاهتان باید راهاندازی مجدد شود. اکنون راهاندازی مجدد کنید یا لغو کنید."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index c899d9c..af278cb 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -61,7 +61,7 @@
<string-array name="bt_hci_snoop_log_entries">
<item msgid="695678520785580527">"Ei käytössä"</item>
<item msgid="6336372935919715515">"Suodatus käytössä"</item>
- <item msgid="2779123106632690576">"Käytössä"</item>
+ <item msgid="2779123106632690576">"Päällä"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="8036025277512210160">"AVRCP 1.4 (oletus)"</item>
@@ -242,7 +242,7 @@
<item msgid="1212561935004167943">"Korosta testatut piirtokom. vihreällä"</item>
</string-array>
<string-array name="track_frame_time_entries">
- <item msgid="634406443901014984">"Pois käytöstä"</item>
+ <item msgid="634406443901014984">"Pois päältä"</item>
<item msgid="1288760936356000927">"Ruudulla palkkeina"</item>
<item msgid="5023908510820531131">"Kohteessa <xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 5fae210..8e82cb2 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -24,7 +24,7 @@
<string name="wifi_security_none" msgid="7392696451280611452">"Ei mitään"</string>
<string name="wifi_remembered" msgid="3266709779723179188">"Tallennettu"</string>
<string name="wifi_disconnected" msgid="7054450256284661757">"Yhteys katkaistu"</string>
- <string name="wifi_disabled_generic" msgid="2651916945380294607">"Pois käytöstä"</string>
+ <string name="wifi_disabled_generic" msgid="2651916945380294607">"Pois päältä"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"IP-kokoonpanovirhe"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Ei yhteyttä – verkko huonolaatuinen"</string>
<string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"Wi-Fi-yhteysvirhe"</string>
@@ -276,7 +276,7 @@
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Striimaus: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Yksityinen DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Valitse yksityinen DNS-tila"</string>
- <string name="private_dns_mode_off" msgid="7065962499349997041">"Pois käytöstä"</string>
+ <string name="private_dns_mode_off" msgid="7065962499349997041">"Pois päältä"</string>
<string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automaattinen"</string>
<string name="private_dns_mode_provider" msgid="3619040641762557028">"Yksityisen DNS-tarjoajan isäntänimi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Anna isäntänimi tai DNS-tarjoaja"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Näytä langattoman näytön sertifiointiin liittyvät asetukset."</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Vähentää virrankulutusta ja parantaa verkon toimintaa"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kun tämä tila on päällä, laitteen MAC-osoite voi muuttua aina, kun laite yhdistää verkkoon, jossa MAC-satunnaistaminen on käytössä."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Maksullinen"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Maksuton"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Lokipuskurien koot"</string>
@@ -399,7 +398,7 @@
</string-array>
<string name="inactive_apps_title" msgid="5372523625297212320">"Valmiustilasovellukset"</string>
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Ei käytössä. Ota käyttöön koskettamalla."</string>
- <string name="inactive_app_active_summary" msgid="8047630990208722344">"Käytössä. Poista käytöstä koskettamalla."</string>
+ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiivinen. Vaihda koskettamalla."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Sovelluksen valmiusluokka: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita."</string>
@@ -456,7 +455,7 @@
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Kytketty virtalähteeseen, lataaminen ei onnistu"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Täynnä"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
- <string name="disabled" msgid="8017887509554714950">"Pois käytöstä"</string>
+ <string name="disabled" msgid="8017887509554714950">"Pois päältä"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Sallittu"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Ei sallittu"</string>
<string name="install_other_apps" msgid="3232595082023199454">"Tuntemattomien sovellusten asentaminen"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Laitteen oletusasetus"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ei käytössä"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peruuta."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 689f267..a144444 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Valeur par défaut de l\'appareil"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (travail)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 6a88f63..f7bfad8 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse e-mail MAC de cet appareil peut changer lors de chaque connexion à un réseau pour lequel le changement aléatoire d\'adresse MAC est activé."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Appareil par défaut"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index c1d5548..08d2eae 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Funcionamento predeterminado"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index b6845a0..b88126b 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"પ્રોફાઇલ પસંદ કરો"</string>
<string name="category_personal" msgid="6236798763159385225">"વ્યક્તિગત"</string>
- <string name="category_work" msgid="4014193632325996115">"કાર્યાલય"</string>
+ <string name="category_work" msgid="4014193632325996115">"ઑફિસ"</string>
<string name="development_settings_title" msgid="140296922921597393">"વિકાસકર્તાનાં વિકલ્પો"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"વિકાસકર્તાનાં વિકલ્પો સક્ષમ કરો"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"ઍપ્લિકેશન વિકાસ માટે વિકલ્પો સેટ કરો"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"બૅટરીનો ચાર્જ ઝડપથી ઓછો થવાનું ટાળે છે અને નેટવર્કની કાર્યક્ષમતામાં સુધારો કરે છે"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"આ મોડ ચાલુ કરેલો હશે, ત્યારે MAC રેન્ડમાઇઝેશન ચાલુ કરેલું હોય તેવા નેટવર્ક સાથે આ ડિવાઇસ જોડાશે ત્યારે દર વખતે તેનું MAC ઍડ્રેસ બદલાય તેમ બની શકે છે."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"મીટર કરેલ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"મીટર ન કરેલ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"લોગર બફર કદ"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
<string name="guest_nickname" msgid="6332276931583337261">"અતિથિ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index aae58c4..7dda73d 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिसप्ले सर्टिफ़िकेशन के विकल्प दिखाएं"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाई-फ़ाई लॉगिंग का स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बैटरी की खपत कम और नेटवर्क की परफ़ॉर्मेंस बेहतर होती है"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"जब यह मोड चालू होता है, तब नेटवर्क से कनेक्ट होने पर हर बार इस डिवाइस का MAC पता बदल सकता है. ऐसा तब होता है, जब डिवाइस किसी ऐसे नेटवर्क से जुड़ता है जिस पर MAC पते को बिना किसी तय नियम के बदलने की सुविधा चालू होती है."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"डेटा इस्तेमाल करने की सीमा तय की गई है"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"डेटा इस्तेमाल करने की सीमा तय नहीं की गई है"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफ़र आकार"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
<string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"डिवाइस की डिफ़ॉल्ट सेटिंग"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद है"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, अपने डिवाइस को फिर से चालू करें. डिवाइस को फिर से चालू करें या रद्द करें."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 64cd891..1db40a8 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -196,7 +196,7 @@
<string name="choose_profile" msgid="343803890897657450">"Odabir profila"</string>
<string name="category_personal" msgid="6236798763159385225">"Osobno"</string>
<string name="category_work" msgid="4014193632325996115">"Posao"</string>
- <string name="development_settings_title" msgid="140296922921597393">"Za razvojne programere"</string>
+ <string name="development_settings_title" msgid="140296922921597393">"Opcije za razvojne programere"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Omogući opcije za razvojne programere"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Postavljanje opcija za razvoj aplikacije"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"Opcije razvojnih programera nisu dostupne za ovog korisnika"</string>
@@ -550,4 +550,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Zadana postavka uređaja"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> za posao"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index ca410f2..4b2132b 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Csökkenti az akkumulátorhasználatot, és javítja a hálózat teljesítményét"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ha ez a mód be van kapcsolva, akkor ennek az eszköznek a MAC-címe minden alkalommal módosulhat, amikor olyan hálózathoz csatlakozik, amelyen engedélyezve van a MAC-címek randomizálása."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Forgalomkorlátos"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Nem forgalomkorlátos"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Naplózási puffer mérete"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Alapértelmezett"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Letiltva"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 22c01ac..11da054 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -38,7 +38,7 @@
<string name="saved_network" msgid="7143698034077223645">"Ով է պահել՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ կերպով միացել է ցանցի վարկանիշի ծառայության մատակարարի միջոցով"</string>
- <string name="connected_via_passpoint" msgid="7735442932429075684">"Կապակցված է %1$s-ի միջոցով"</string>
+ <string name="connected_via_passpoint" msgid="7735442932429075684">"Միացված է %1$s-ի միջոցով"</string>
<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>
@@ -99,7 +99,7 @@
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Միացված է հեռախոսի ձայնային տվյալներին"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Միացված է ֆայլերի փոխանցման սերվերին"</string>
<string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"Միացված է քարտեզին"</string>
- <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Կապակցված է SAP-ին"</string>
+ <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Միացված է SAP-ին"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Ֆայլերը փոխանցող սերվերի հետ կապ չկա"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Միացված է մուտքային սարքին"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Միացված է սարքին` ինտերնետ մտնելու համար"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Հյուր"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Կանխադրված տարբերակ"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Անջատված է"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index a578d31..3b02fbf 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tamu"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Default perangkat"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Nonaktif"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 862dabd..6560de0 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Sjálfgefin stilling tækis"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slökkt"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index ff3df16..ece0ba4 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -207,11 +207,11 @@
<string name="enable_adb_summary" msgid="3711526030096574316">"Modalità debug quando è connesso tramite USB"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"Revoca autorizzazioni debug USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Debug wireless"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modalità Debug quando il Wi-Fi è connesso"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modalità debug quando il Wi-Fi è connesso"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Errore"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Debug wireless"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Per trovare e utilizzare i dispositivi disponibili, attiva il debug wireless"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Accoppia il dispositivo con il codice QR"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Accoppia dispositivo con codice QR"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Accoppia i nuovi dispositivi utilizzando lo scanner di codici QR"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Accoppia dispositivo con codice di accoppiamento"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Accoppia i nuovi dispositivi utilizzando un codice di sei cifre"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opzioni per la certificazione display wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta livello di logging Wi-Fi, mostra SSID RSSI nel selettore Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Riduce il consumo della batteria e migliora le prestazioni della rete"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando questa modalità è attiva, l\'indirizzo MAC del dispositivo potrebbe cambiare ogni volta che si connette a una rete con randomizzazione MAC attivata"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando questa modalità è attiva, l\'indirizzo MAC del dispositivo potrebbe cambiare ogni volta che si connette a una rete con randomizzazione MAC attivata."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"A consumo"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non a consumo"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Dimensioni buffer logger"</string>
@@ -359,7 +359,7 @@
<string name="track_frame_time" msgid="522674651937771106">"Rendering HWUI profilo"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Attiva livelli debug GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Consenti caricamento livelli debug GPU per app di debug"</string>
- <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Attiva reg. dettagl. fornitori"</string>
+ <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Attiva log dettagliati fornitori"</string>
<string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Includi log aggiuntivi di fornitori relativi a un dispositivo specifico nelle segnalazioni di bug che potrebbero contenere informazioni private, causare un maggior consumo della batteria e/o utilizzare più spazio di archiviazione."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Scala animazione finestra"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Scala animazione transizione"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predefinito dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Non attivo"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Devi riavviare il dispositivo per applicare questa modifica. Riavvia ora o annulla."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index ca0849e..23e701d 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"הצג אפשרויות עבור אישור של תצוגת WiFi"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"מפחית את קצב התרוקנות הסוללה ומשפר את ביצועי הרשת"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"כשמצב זה מופעל, כתובת ה-MAC של המכשיר הזה עשויה להשתנות בכל פעם שהוא מתחבר לרשת שפועלת בה רנדומיזציה של כתובות MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"נמדדת"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"לא נמדדת"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"גדלי מאגר של יומן רישום"</string>
@@ -552,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח"</string>
<string name="guest_nickname" msgid="6332276931583337261">"אורח"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ברירת המחדל של המכשיר"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"מושבת"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 604ceb2..7640722 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ワイヤレス ディスプレイ認証のオプションを表示"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ログレベルを上げて、Wi-Fi 選択ツールで SSID RSSI ごとに表示します"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"電池の消耗が軽減され、ネットワーク パフォーマンスが改善されます"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"このモードが有効な場合、このデバイスは、MAC アドレスのランダム化が有効なネットワークに接続するたびに MAC アドレスが変わる可能性があります。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"従量制"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"定額制"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ログバッファのサイズ"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ゲスト"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"デバイスのデフォルト"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"無効"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動してください。キャンセルすることもできます。"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 754d4a0..985188f 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"სტუმრის დამატება"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"სტუმრის ამოშლა"</string>
<string name="guest_nickname" msgid="6332276931583337261">"სტუმარი"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"მოწყობილობის ნაგულისხმევი"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"გათიშული"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ჩართული"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"სამსახურის <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 50ff04d..a5308e4 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Сымсыз дисплей сертификаты опцияларын көрсету"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi тіркеу деңгейін арттыру, Wi‑Fi таңдағанда әр SSID RSSI бойынша көрсету"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарея зарядының шығынын азайтады және желі жұмысын жақсартады."</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Бұл режим қосулы болса, құрылғының MAC мекенжайы MAC рандомизациясы қосулы желіге жалғанған сайын өзгеруі мүмкін."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Трафик саналады"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Трафик саналмайды"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Журналға тіркеуші буферінің өлшемдері"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақты енгізу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты өшіру"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Құрылғыны әдепкісінше реттеу"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өшірулі"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 92ea817..0ff48e1 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"បង្ហាញជម្រើសសម្រាប់សេចក្តីបញ្ជាក់ការបង្ហាញឥតខ្សែ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"បង្កើនកម្រិតកំណត់ហេតុ Wi-Fi បង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសរើស Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"កាត់បន្ថយការប្រើប្រាស់ថ្ម និងកែលម្អប្រតិបត្តិការបណ្ដាញ"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"នៅពេលបើកមុខងារនេះ អាសយដ្ឋាន MAC របស់ឧបករណ៍នេះអាចផ្លាស់ប្ដូរ រាល់ពេលដែលវាភ្ជាប់ជាមួយបណ្ដាញដែលបានបើកការតម្រៀប MAC តាមលំដាប់ចៃដន្យ។"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"មានការកំណត់"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"មិនមានការកំណត់"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ទំហំកន្លែងផ្ទុករបស់ logger"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូលភ្ញៀវ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"លុបភ្ញៀវ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"លំនាំដើមរបស់ឧបករណ៍"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"បានបិទ"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែចាប់ផ្ដើមឧបករណ៍របស់អ្នកឡើងវិញ ទើបការផ្លាស់ប្ដូរនេះត្រូវបានអនុវត្ត។ ចាប់ផ្ដើមឡើងវិញឥឡូវនេះ ឬបោះបង់។"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index f495857..52e3b99 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -549,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 782791a..b8d587b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -210,7 +210,7 @@
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi가 연결되었을 때 디버그 모드 사용"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"오류"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"무선 디버깅"</string>
- <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"사용 가능한 기기를 보고 사용하려면 무선 디버깅을 사용 설정하세요."</string>
+ <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"사용 가능한 기기를 확인하고 사용하려면 무선 디버깅을 사용 설정하세요."</string>
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR 코드로 기기 페어링"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR 코드 스캐너를 사용하여 새 기기 페어링"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"페어링 코드로 기기 페어링"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string>
<string name="guest_nickname" msgid="6332276931583337261">"게스트"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"기기 기본값"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"사용 중지됨"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 3d93110..3c57c79 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -203,29 +203,29 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"Бул колдонуучу VPN жөндөөлөрүн колдоно албайт"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"Бул колдонуучу модем режиминин жөндөөлөрүн өзгөртө албайт"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Бул колдонуучу мүмкүндүк алуу түйүнүнүн аталышынын жөндөөлөрүн колдоно албайт"</string>
- <string name="enable_adb" msgid="8072776357237289039">"USB аркылуу мүчүлүштүктөрдү оңдоо"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"USB аркылуу мүчүлүштүктөрдү аныктоо"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"USB компьютерге сайылганда мүчүлүштүктөрдү оңдоо режими иштейт"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"USB аркылуу мүчүлүштүктөрдү оңдоо уруксатын артка кайтаруу"</string>
- <string name="enable_adb_wireless" msgid="6973226350963971018">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi\'га туташтырылганда мүчүлүштүктөрдү оңдоо режими"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"USB аркылуу мүчүлүштүктөрдү аныктоо уруксатын артка кайтаруу"</string>
+ <string name="enable_adb_wireless" msgid="6973226350963971018">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi\'га туташканда, мүчүлүштүктөрдү аныктоо режими иштейт оңдоо режими"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Ката"</string>
- <string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо"</string>
- <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн мүчүлүштүктөрдү Wi-Fi аркылуу оңдоону күйгүзүңүз"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR кодун колдонуп, түзмөктү жупташтырыңыз"</string>
+ <string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо"</string>
+ <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн, мүчүлүштүктөрдү Wi-Fi аркылуу аныктоону күйгүзүңүз"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Түзмөктү QR коду аркылуу жупташтыруу"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR кодунун сканерин колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Жупташтыруучу код менен түзмөктү жупташтырыңыз"</string>
- <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Алты сандан турган кодду колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Түзмөктү атайын код аркылуу жупташтыруу"</string>
+ <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Жаңы түзмөктөрдү алты сандан турган код аркылуу жупташтырасыз"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Жупташтырылган түзмөктөр"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Учурда туташып турган түзмөктөр"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Түзмөктүн чоо-жайы"</string>
<string name="adb_device_forget" msgid="193072400783068417">"Унутулсун"</string>
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Түзмөктөгү манжа изи: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
- <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Туташкан жок"</string>
+ <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Байланышкан жок"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> туура тармакка туташып турганын текшериңиз"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Түзмөктү жупташтыруу"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi жупташтыруучу коду"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Жупташтырылган жок"</string>
- <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Түзмөк бир тармакка туташканын текшериңиз."</string>
+ <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Түзмөк бир тармакка туташып турушу керек."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR кодун скандап, түзмөктү Wi‑Fi аркылуу жупташтырыңыз"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Түзмөк жупташтырылууда…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Түзмөк жупташтырылган жок. QR коду туура эмес же түзмөк бир тармакка туташпай турат."</string>
@@ -303,7 +303,7 @@
<string name="adb_warning_title" msgid="7708653449506485728">"USB аркылуу жөндөөгө уруксат бересизби?"</string>
<string name="adb_warning_message" msgid="8145270656419669221">"USB-жөндөө - өндүрүү максатында гана түзүлгөн. Аны компүтериңиз менен түзмөгүңүздүн ортосунда берилиштерди алмашуу, түзмөгүңүзгө колдонмолорду эскертүүсүз орнотуу жана лог берилиштерин окуу үчүн колдонсоңуз болот."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат берилсинби?"</string>
- <string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string>
+ <string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"Сиз мурун USB жөндөөлөрүнө уруксат берген бардык компүтерлердин жеткиси жокко чыгарылсынбы?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Жөндөөлөрдү өзгөртүү"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
@@ -317,7 +317,7 @@
<string name="enable_terminal_summary" msgid="2481074834856064500">"Жергиликтүү буйрук кабыгын сунуштаган терминалга уруксат берүү"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP текшерүү"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP текшерүү тартиби"</string>
- <string name="debug_debugging_category" msgid="535341063709248842">"Мүчүлүштүктөрдү оңдоо"</string>
+ <string name="debug_debugging_category" msgid="535341063709248842">"Мүчүлүштүктөрдү аныктоо"</string>
<string name="debug_app" msgid="8903350241392391766">"Мүчүлүштүктөрдү оңдоочу колдонмону тандоо"</string>
<string name="debug_app_not_set" msgid="1934083001283807188">"Бир дагы колдонмо орнотула элек."</string>
<string name="debug_app_set" msgid="6599535090477753651">"Жөндөөчү колдонмо: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -360,7 +360,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU мүчүлүштүктөрдү оңдоо катмарларын иштетүү"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"GPU мүчүлүштүктөрдү оңдоо катмарларын иштетет"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Кызмат көрсөтүүчүнү оозеки киргизүүнү иштетет"</string>
- <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Түзмөккө байланыштуу кызмат көрсөтүүчүнүн кирүүлөрү боюнча мүчүлүштүк тууралуу кабар берүү камтылсын. Анда купуя маалымат көрсөтүлүп, батарея тезирээк отуруп жана/же сактагычтан көбүрөөк орун ээлениши мүмкүн."</string>
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Түзмөккө байланыштуу кызмат көрсөтүүчүнүн кирүүлөрү боюнча мүчүлүштүк тууралуу кабарлоо камтылсын. Анда купуя маалымат көрсөтүлүп, батарея тезирээк отуруп жана/же сактагычтан көбүрөөк орун ээлениши мүмкүн."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Терезелердин анимациясы"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Өткөрүү анимацснн шкаласы"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Анимациянын узактыгы"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Конок"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Түзмөктүн демейки параметри"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өчүк"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөртүүнү колдонуу үчүн түзмөктү өчүрүп күйгүзүңүз. Азыр өчүрүп күйгүзүңүз же жокко чыгарыңыз."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 856f26c..02f73b5 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ແຂກ"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ຄ່າເລີ່ມຕົ້ນອຸປະກອນ"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ປິດການນຳໃຊ້ແລ້ວ"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ບ່ອນເຮັດວຽກ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index eefc709..dc6347a 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sumažinamas akumuliatoriaus eikvojimas ir patobulinamas tinklo našumas"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kai įgalintas šis režimas, šio įrenginio MAC adresas gali keistis kas kartą prisijungus prie tinklo, kuriame įgalintas atsitiktinis MAC parinkimas."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Matuojamas"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neišmatuotas"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Registruotuvo buferio dydžiai"</string>
@@ -552,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Numatyt. įrenginio nustatymas"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Išjungta"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 758fba7..0a185d0 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -550,4 +550,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Ierīces noklusējums"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Atspējots"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index a662cd3..e0cc38d 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Додај гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандардно за уредот"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Оневозможено"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1af22b2..1a3f068 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"അജ്ഞാതം"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ഉപയോക്താവ്: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"സ്ഥിരമായ ചിലത് സജ്ജീകരിച്ചു"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"സ്ഥിരമായൊന്നും സജ്ജീകരിച്ചിട്ടില്ല"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"ഡിഫോൾട്ടുകളൊന്നും സജ്ജീകരിച്ചിട്ടില്ല"</string>
<string name="tts_settings" msgid="8130616705989351312">"ടെക്സ്റ്റ്-ടു-സ്പീച്ച് ക്രമീകരണങ്ങൾ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ടെക്സ്റ്റ്-ടു-സ്പീച്ച് ഔട്ട്പുട്ട്"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"വായനയുടെ വേഗത"</string>
@@ -207,7 +207,7 @@
<string name="enable_adb_summary" msgid="3711526030096574316">"USB കണക്റ്റുചെയ്തിരിക്കുമ്പോഴുള്ള ഡീബഗ് മോഡ്"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"USB ഡീബഗ്ഗിംഗ് അംഗീകാരം പിൻവലിക്കുക"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"വയർലെസ് ഡീബഗ്ഗിംഗ്"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"വൈഫൈ കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ ഡീബഗ് ചെയ്യൽ മോഡിലാക്കുക"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"വൈഫൈ കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ ഡീബഗ് മോഡിലാക്കുക"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"പിശക്"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"വയർലെസ് ഡീബഗ്ഗിംഗ്"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ലഭ്യമായ ഉപകരണങ്ങൾ കാണാനും ഉപയോഗിക്കാനും വയർലെസ് ഡീബഗ്ഗിംഗ് ഓണാക്കുക"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ബാറ്ററി ചാർജ് വേഗത്തിൽ തീരുന്ന അവസ്ഥ കുറച്ച് നെറ്റ്വർക്ക് പ്രകടനം മെച്ചപ്പെടുത്തുന്നു"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ഈ മോഡ് പ്രവർത്തനക്ഷമമാക്കുമ്പോൾ, MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്ന നെറ്റ്വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുമ്പോഴെല്ലാം ഈ ഉപകരണത്തിന്റെ MAC വിലാസം മാറിയേക്കാം."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"മീറ്റർ ചെയ്തത്"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"മീറ്റർമാപകമല്ലാത്തത്"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ലോഗർ ബഫർ വലുപ്പം"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
<string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 05e1393..a342862 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Төхөөрөмжийн өгөгдмөл"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Идэвхгүй болгосон"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл болино уу."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index e5f6764..0895cd4 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाय-फाय लॉगिंग स्तर वाढवा, वाय-फाय सिलेक्टरमध्ये प्रति SSID RSSI दर्शवा"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बॅटरी जलदरीतीने संपण्यापासून रोखते आणि नेटवर्क परफॉर्मन्समध्ये सुधारणा करते"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"हा मोड सुरू केला असल्यास, या डिव्हाइसचा MAC अॅड्रेस प्रत्येक वेळी MAC रँडमायझेशन सुरू असलेल्या नेटवर्कशी कनेक्ट झाल्यास, कदाचित बदलू शकतो."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"मीटरने मोजलेले"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"मीटरने न मोजलेले"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफर आकार"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index c6be11f..a1c6782 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Mengurangkan penyusutan bateri & meningkatkan prestasi rangkaian"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Apabila mod ini didayakan, alamat MAC peranti ini mungkin berubah setiap kali peranti bersambung kepada rangkaian yang telah mendayakan perawakan MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Bermeter"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak bermeter"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Saiz penimbal pengelog"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tetamu"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Lalai peranti"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dilumpuhkan"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 037436e..0edc100 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"စက်ပစ္စည်းမူရင်း"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ပိတ်ထားသည်"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 1ab840c..d683070 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Standard for enheten"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slått av"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 7c6785b..ee22c60 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ब्याट्रीको खपत कम गरी नेटवर्कको कार्यसम्पादनमा सुधार गर्दछ"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"यो मोड अन गरिएका बेला यो यन्त्र MAC ठेगाना बदल्ने सुविधा अन गरिएको कुनै इन्टरनेटसँग जति पटक कनेक्ट हुन्छ त्यति नै पटक यस यन्त्रको MAC ठेगाना पनि परिवर्तन हुन सक्छ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"सशुल्क वाइफाइ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"मिटर नगरिएको"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लगर बफर आकारहरू"</string>
@@ -375,7 +374,7 @@
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना च्यानलका चेतावनी देखाउनुहोस्"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"अनुप्रयोगले कुनै मान्य च्यानल बिना सूचना पोस्ट गर्दा स्क्रिनमा चेतावनी देखाउँछ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"बाह्यमा बल प्रयोगको अनुमति प्राप्त एपहरू"</string>
- <string name="force_allow_on_external_summary" msgid="8525425782530728238">"म्यानिफेेस्टका मानहरूको ख्याल नगरी कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न सकिने खाले बनाउँछ"</string>
+ <string name="force_allow_on_external_summary" msgid="8525425782530728238">"म्यानिफेेस्टका मानहरूको ख्याल नगरी कुनै पनि एपलाई बाह्य भण्डारणमा लेख्न सकिने खाले बनाउँछ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"आकार बदल्न योग्य हुने बनाउन गतिविधिहरूलाई बाध्यात्मक बनाउनुहोस्।"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउनुहोस्।"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"फ्रिफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
@@ -429,10 +428,10 @@
<string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"तपाईंको प्रयोगको आधारमा लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<!-- no translation found for power_remaining_duration_only_short (7438846066602840588) -->
<skip />
- <string name="power_discharge_by_enhanced" msgid="563438403581662942">"तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ"</string>
- <string name="power_discharge_by" msgid="4113180890060388350">"ब्याट्री लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_discharge_by_only" msgid="92545648425937000">"लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ"</string>
+ <string name="power_discharge_by_enhanced" msgid="563438403581662942">"तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्छ"</string>
+ <string name="power_discharge_by" msgid="4113180890060388350">"ब्याट्री लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_discharge_by_only" msgid="92545648425937000">"लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्छ"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> सम्म"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ब्याट्री <xliff:g id="TIME">%1$s</xliff:g> बजेसम्ममा सकिन सक्छ"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी छ"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथि"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 417cd95..dc5f8f2 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Apparaatstandaard"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Uitgeschakeld"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ingeschakeld"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> voor werk"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
index a021446..5928a87 100644
--- a/packages/SettingsLib/res/values-or/arrays.xml
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -156,7 +156,7 @@
<item msgid="5001852592115448348">", ସକ୍ରିୟ (ଫୋନ୍)"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="1191094707770726722">"ଅଫ୍"</item>
+ <item msgid="1191094707770726722">"ବନ୍ଦ"</item>
<item msgid="7839165897132179888">"64K"</item>
<item msgid="2715700596495505626">"256K"</item>
<item msgid="7099386891713159947">"1M"</item>
@@ -184,7 +184,7 @@
<item msgid="7300881231043255746">"କେବଳ କର୍ନେଲ୍"</item>
</string-array>
<string-array name="select_logpersist_summaries">
- <item msgid="97587758561106269">"ଅଫ"</item>
+ <item msgid="97587758561106269">"ବନ୍ଦ"</item>
<item msgid="7126170197336963369">"ସମସ୍ତ ଲଗ୍ ବଫର୍"</item>
<item msgid="7167543126036181392">"ରେଡିଓ ଲଗ୍ ବଫର୍ଗୁଡିକ ଛଡ଼ା ଅନ୍ୟ ସବୁ"</item>
<item msgid="5135340178556563979">"କେବଳ କର୍ନେଲ୍ ଲଗ୍ ବଫର୍"</item>
@@ -237,7 +237,7 @@
<item msgid="7345673972166571060">"glGetError ରେ କଲ୍ ଷ୍ଟାକ୍"</item>
</string-array>
<string-array name="show_non_rect_clip_entries">
- <item msgid="2482978351289846212">"ଅଫ୍"</item>
+ <item msgid="2482978351289846212">"ବନ୍ଦ"</item>
<item msgid="3405519300199774027">"ଅଣ-ଆୟତାକାର କ୍ଲିପ୍ କ୍ଷେତ୍ର ନୀଳ ରଙ୍ଗରେ ଆଙ୍କନ୍ତୁ"</item>
<item msgid="1212561935004167943">"ଟେଷ୍ଟ ହୋଇଥିବା ଅଙ୍କନ କମାଣ୍ଡଗୁଡ଼ିକୁ ସବୁଜରେ ଚିହ୍ନିତ କରନ୍ତୁ"</item>
</string-array>
@@ -247,7 +247,7 @@
<item msgid="5023908510820531131">"ରେ <xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>"</item>
</string-array>
<string-array name="debug_hw_overdraw_entries">
- <item msgid="1968128556747588800">"ଅଫ୍"</item>
+ <item msgid="1968128556747588800">"ବନ୍ଦ"</item>
<item msgid="3033215374382962216">"ଓଭର୍ ଡ୍ର କ୍ଷେତ୍ରଗୁଡ଼ିକୁ ଦେଖାଅ"</item>
<item msgid="3474333938380896988">"ଡିଉଟେରାନୋମାଲୀ ପାଇଁ କ୍ଷେତ୍ର ଦେଖନ୍ତୁ"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 74c1477..18cc9e3 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"ଅଜଣା"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ଉପଯୋଗକର୍ତ୍ତା: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"କିଛି ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ ମାନ ସେଟ୍ ହୋଇଛି"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"କୌଣସି ପୂର୍ବ-ନିର୍ଦ୍ଧାରଣ ସେଟ୍ ହୋଇନାହିଁ"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"କୌଣସି ଡିଫଲ୍ଟ ସେଟ୍ ହୋଇନାହିଁ"</string>
<string name="tts_settings" msgid="8130616705989351312">"ଟେକ୍ସଟ-ରୁ-ସ୍ପିଚ୍ ସେଟିଂସ୍"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ଟେକ୍ସଟ-ରୁ-ସ୍ପିଚ୍ ଆଉଟପୁଟ୍"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"ସ୍ପିଚ୍ ରେଟ୍"</string>
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"ପ୍ରୋଫାଇଲ୍ ବାଛନ୍ତୁ"</string>
<string name="category_personal" msgid="6236798763159385225">"ବ୍ୟକ୍ତିଗତ"</string>
- <string name="category_work" msgid="4014193632325996115">"କାମ"</string>
+ <string name="category_work" msgid="4014193632325996115">"ୱାର୍କ"</string>
<string name="development_settings_title" msgid="140296922921597393">"ଡେଭଲପର୍ଙ୍କ ପାଇଁ ବିକଳ୍ପମାନ"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"ଡେଭଲପର୍ ବିକଳ୍ପଗୁଡ଼ିକ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"ଆପ୍ର ବିକାଶ ପାଇଁ ବିକଳ୍ପମାନ ସେଟ୍ କରନ୍ତୁ"</string>
@@ -203,9 +203,9 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନୁହେଁ"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଙ୍ଗ ସେଟିଙ୍ଗ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"ଆକ୍ସେସ୍ ପଏଣ୍ଟ ନାମର ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗ୍ ହେଉଛି"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗିଂ"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"USB ସଂଯୁକ୍ତ ହେବାବେଳେ ଡିବଗ୍ ମୋଡ୍"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଙ୍ଗ ଅଧିକାରକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଂ ଅଧିକାରକୁ ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"ୱାୟାରଲେସ୍ ଡିବଗିଂ"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"ୱାଇ-ଫାଇ ସଂଯୁକ୍ତ ଥିବା ବେଳେ ଡିବଗ୍ ମୋଡ୍"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"ତ୍ରୁଟି"</string>
@@ -222,7 +222,7 @@
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"ଡିଭାଇସ୍ ଫିଙ୍ଗରପ୍ରିଣ୍ଟ: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"ସଂଯୋଗ ବିଫଳ ହେଲା"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ଫୋନ୍ ନେଟୱାର୍କ ସହ ସଂଯୁକ୍ତ ଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
- <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"ଡିଭାଇସରୁ ପେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"ଡିଭାଇସରେ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"ୱାଇ-ଫାଇ ପେୟାରିଂ କୋଡ୍"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"ପେୟାରିଂ ବିଫଳ ହେଲା"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"ଡିଭାଇସଟି ସମାନ ନେଟୱାର୍କରେ ସଂଯୋଗ ହୋଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
@@ -276,7 +276,7 @@
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"ଷ୍ଟ୍ରିମ୍ କରୁଛି: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="7887550926056143018">"ବ୍ୟକ୍ତିଗତ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"ବ୍ୟକ୍ତିଗତ DNS ମୋଡ୍ ବାଛନ୍ତୁ"</string>
- <string name="private_dns_mode_off" msgid="7065962499349997041">"ଅଫ୍"</string>
+ <string name="private_dns_mode_off" msgid="7065962499349997041">"ବନ୍ଦ"</string>
<string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"ସ୍ଵଚାଳିତ"</string>
<string name="private_dns_mode_provider" msgid="3619040641762557028">"ବ୍ୟକ୍ତିଗତ DNS ପ୍ରଦାତା ହୋଷ୍ଟନାମ"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"DNS ପ୍ରଦାନକାରୀଙ୍କ ହୋଷ୍ଟନାମ ଲେଖନ୍ତୁ"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ୱେୟାରଲେସ୍ ଡିସ୍ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପ ଦେଖାନ୍ତୁ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍ୱାର୍କ କାର୍ଯ୍ୟକ୍ଷମତା ଉନ୍ନତ କରିଥାଏ"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ଯେତେବେଳେ ଏହି ମୋଡ୍ ସକ୍ଷମ ହୁଏ, ପ୍ରତ୍ୟେକ ଥର MAC ରେଣ୍ଡୋମାଇଜେସନ୍ ସକ୍ଷମ ଥିବା କୌଣସି ନେଟୱାର୍କ ସହ ଏହି ଡିଭାଇସ୍ ସଂଯୋଗ ହେଲେ ଏହାର MAC ଠିକଣା ବଦଳିପାରେ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ମପାଯାଉଥିବା"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ମପାଯାଉନଥିବା"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ଲଗର୍ ବଫର୍ ସାଇଜ୍"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ଅତିଥି"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 68cc061..b502f3f 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -549,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ਮਹਿਮਾਨ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 43b8f5f..552ef6b 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -29,7 +29,7 @@
<item msgid="4613015005934755724">"Połączono"</item>
<item msgid="3763530049995655072">"Zawieszona"</item>
<item msgid="7852381437933824454">"Trwa rozłączanie..."</item>
- <item msgid="5046795712175415059">"Rozłączona"</item>
+ <item msgid="5046795712175415059">"Rozłączono"</item>
<item msgid="2473654476624070462">"Niepowodzenie"</item>
<item msgid="9146847076036105115">"Zablokowana"</item>
<item msgid="4543924085816294893">"Tymczasowo, by uniknąć połączenia o niskiej jakości"</item>
@@ -43,7 +43,7 @@
<item msgid="1043944043827424501">"Połączono z siecią <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Zawieszona"</item>
<item msgid="1175040558087735707">"Trwa rozłączanie z siecią <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
- <item msgid="699832486578171722">"Rozłączona"</item>
+ <item msgid="699832486578171722">"Rozłączono"</item>
<item msgid="522383512264986901">"Niepowodzenie"</item>
<item msgid="3602596701217484364">"Zablokowana"</item>
<item msgid="1999413958589971747">"Tymczasowo, by uniknąć połączenia o niskiej jakości"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 9db0f5e..8a29bf0 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -23,7 +23,7 @@
<string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nie można wyszukać sieci."</string>
<string name="wifi_security_none" msgid="7392696451280611452">"Brak"</string>
<string name="wifi_remembered" msgid="3266709779723179188">"Zapisana"</string>
- <string name="wifi_disconnected" msgid="7054450256284661757">"Rozłączona"</string>
+ <string name="wifi_disconnected" msgid="7054450256284661757">"Rozłączono"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"Wyłączona"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Błąd konfiguracji IP"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Brak połączenia z powodu słabego sygnału sieci"</string>
@@ -63,7 +63,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"Bardzo szybka"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"Ważność wygasła"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"Rozłączona"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"Rozłączono"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Rozłączanie..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Łączenie..."</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Połączono – <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Wybierz profil"</string>
<string name="category_personal" msgid="6236798763159385225">"Osobiste"</string>
- <string name="category_work" msgid="4014193632325996115">"Służbowe"</string>
+ <string name="category_work" msgid="4014193632325996115">"Do pracy"</string>
<string name="development_settings_title" msgid="140296922921597393">"Opcje programistyczne"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Włącz opcje dla programistów"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Ustaw opcje związane z programowaniem aplikacji."</string>
@@ -551,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gość"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Ustawienie domyślne urządzenia"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Wyłączono"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Włączono"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Wprowadzenie zmiany wymaga ponownego uruchomienia urządzenia. Uruchom ponownie teraz lub anuluj."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index b33b2b5..58a13cd 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -223,7 +223,7 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Falha na conexão"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Verifique se o <xliff:g id="DEVICE_NAME">%1$s</xliff:g> está conectado à rede correta"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Parear com o dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento por Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Falha no pareamento"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Verifique se o dispositivo está conectado à mesma rede."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Padrão do dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"App <xliff:g id="APP_NAME">%s</xliff:g> de trabalho"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 36b8468..ca85151 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predefinição do dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativada"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> de trabalho"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index b33b2b5..58a13cd 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -223,7 +223,7 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Falha na conexão"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Verifique se o <xliff:g id="DEVICE_NAME">%1$s</xliff:g> está conectado à rede correta"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Parear com o dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento por Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Falha no pareamento"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Verifique se o dispositivo está conectado à mesma rede."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
@@ -549,4 +549,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Padrão do dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"App <xliff:g id="APP_NAME">%s</xliff:g> de trabalho"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index e784873..f967c8c 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -550,4 +550,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Prestabilit pentru dispozitiv"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dezactivat"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să reporniți dispozitivul. Reporniți-l acum sau anulați."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index bdda5ee..e41b3b7 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -551,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить аккаунт гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Вариант по умолчанию"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Отключено"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index ba710e2..5710985 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
<string name="guest_nickname" msgid="6332276931583337261">"අමුත්තා"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"උපාංගයේ පෙරනිමිය"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"අබල කළා"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 5abba6f..b3848a9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -211,9 +211,9 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Chyba"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Bezdrôtové ladenie"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ak chcete zobraziť a používať dostupné zariadenia, zapnite bezdrôtové ladenie"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Spárovať zariadenie pomocou QR kódu"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Spárovať zariadenie QR kódom"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Spárujte nové zariadenia pomocou skenera QR kódov"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Spárovať zariadenie pomocou párovacieho kódu"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Spárovať zariadenie párovacím kódom"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Spárujte nové zariadenia pomocou šesťmiestneho kódu"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Spárované zariadenia"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Aktuálne pripojené"</string>
@@ -226,15 +226,15 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Párovací kód siete Wi-Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Párovanie zlyhalo"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Skontrolujte, či je zariadenie pripojené k rovnakej sieti."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Spárujte zariadenie cez sieť Wi-Fi naskenovaním QR kódu"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Spárujte zariadenie cez Wi-Fi naskenovaním QR kódu"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Páruje sa zariadenie…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Zariadenie sa nepodarilo spárovať. Buď bol QR kód nesprávny, alebo zariadenie nie je pripojené k rovnakej sieti."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresa IP a port"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Naskenujte QR kód"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Spárujte zariadenie cez sieť Wi-Fi naskenovaním QR kódu"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Spárujte zariadenie cez Wi-Fi naskenovaním QR kódu"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Pripojte sa k sieti Wi‑Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ladenie, dev"</string>
- <string name="bugreport_in_power" msgid="8664089072534638709">"Skratka hlásenia chyby"</string>
+ <string name="bugreport_in_power" msgid="8664089072534638709">"Odkaz na hlásenie chyby"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"Zobraziť v hlavnej ponuke tlačidlo na vytvorenie hlásenia chyby"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"Nevypínať obrazovku"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"Obrazovka sa pri nabíjaní neprepne do režimu spánku"</string>
@@ -551,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predvol. nastavenie zariadenia"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuté"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Táto zmena sa uplatní až po reštartovaní zariadenia. Zariadenie reštartujte alebo zmenu zrušte."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index b0c6117..658c192 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -72,14 +72,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Povezano (brez predstavnosti) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Povezano (brez dostopa do sporočil) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"Povezano (brez telefona/predstavnosti) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Povezano, raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Povezano (brez telefona), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Povezano (brez predstavnosti), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Povezano (brez telefona ali predstavnosti), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivna, akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Povezano, raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Povezano (brez telefona), raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Povezano (brez predstavnosti), raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Povezano (brez telefona ali predstavnosti), raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivna, baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivna"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvok predstavnosti"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski klici"</string>
@@ -129,8 +129,8 @@
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Seznanjanje z levim slušnim pripomočkom …"</string>
<string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Seznanjanje z desnim slušnim pripomočkom …"</string>
- <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Levi – akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Desni – akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Levi – baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Desni – baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi je izklopljen."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Povezava Wi-Fi je prekinjena."</string>
<string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Ena črtica signala Wi-Fi."</string>
@@ -283,9 +283,8 @@
<string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Povezave ni bilo mogoče vzpostaviti"</string>
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povečaj raven zapisovanja dnevnika za Wi-Fi; v izbirniku Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
- <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije akumulatorja in izboljša delovanje omrežja"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije baterije in izboljša delovanje omrežja"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ko je ta način omogočen, se lahko naslov MAC te naprave spremeni vsakič, ko se naprava poveže v omrežje z omogočenim naključnim dodeljevanjem naslova MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Omejen prenos podatkov"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Z neomejenim prenosom podatkov"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Velikosti medpomnilnikov zapisovalnika dnevnika"</string>
@@ -552,4 +551,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Privzeta nastavitev naprave"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogočeno"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string>
+ <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> za delo"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 71f62d4..17d2d50 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Shfaq opsionet për certifikimin e ekranit valor"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zvogëlon shkarkimin e baterisë dhe përmirëson cilësinë e funksionimit të rrjetit"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kur ky modalitet është i aktivizuar, adresa MAC e kësaj pajisjeje mund të ndryshojë çdo herë që lidhet me një rrjet që ka të aktivizuar renditjen e rastësishme të adresave MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Me matje"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Pa matje"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Madhësitë e regjistruesit"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"I ftuar"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Parazgjedhja e pajisjes"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Joaktiv"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 15df19c..e0a7d0b 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -143,11 +143,11 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Уклоњене апликације"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Уклоњене апликације и корисници"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Ажурирања система"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB Интернет повезивање"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB привезивање"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Преносни хотспот"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth привезивање"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Повезивање са интернетом"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Повезивање и преносни хотспот"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Привезивање"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Привезивање и преносни хотспот"</string>
<string name="managed_user_title" msgid="449081789742645723">"Све радне апликације"</string>
<string name="user_guest" msgid="6939192779649870792">"Гост"</string>
<string name="unknown" msgid="3544487229740637809">"Непознато"</string>
@@ -550,4 +550,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Подразумевано за уређај"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Онемогућено"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 6b1a63c..f6745b2 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Enhetens standardinställning"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inaktiverat"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index e041bea..7df39d5 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -224,7 +224,7 @@
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Hakikisha kuwa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kimeunganishwa kwenye mtandao sahihi"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Oanisha na kifaa"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Msimbo wa kuoanisha wa Wi-Fi"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Imeshindwa kuunganisha"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Imeshindwa kuoanisha"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Hakikisha kuwa kifaa kimeunganishwa kwenye mtandao mmoja."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Oanisha kifaa kupitia Wi-Fi kwa kuchanganua msimbo wa QR"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Inaoanisha kifaa…"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Weka mgeni"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Hali chaguomsingi ya kifaa"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Imezimwa"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index d403858..fa922ea 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வுக் கருவியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"பேட்டரி தீர்ந்துபோவதைக் குறைத்து நெட்வொர்க்கின் செயல்திறனை மேம்படுத்தும்"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"இந்தப் பயன்முறை இயக்கப்படும்போது இந்தச் சாதனத்தின் MAC முகவரியானது ஒவ்வொரு முறை MAC ரேண்டம் ஆக்குதல் இயக்கப்பட்டிருக்கும் நெட்வொர்க்குடன் இணைக்கப்படும்போதும் மாறக்கூடும்."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"கட்டண நெட்வொர்க்"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"கட்டணமில்லா நெட்வொர்க்"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"லாகர் பஃபர் அளவுகள்"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string>
<string name="guest_nickname" msgid="6332276931583337261">"கெஸ்ட்"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"சாதனத்தின் இயல்புநிலை"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"முடக்கப்பட்டது"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 3c86509..0e36c5f 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"తెలియదు"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"వినియోగదారు: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"కొన్ని డిఫాల్ట్లు సెట్ చేయబడ్డాయి"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"డిఫాల్ట్లు ఏవీ సెట్ చేయబడలేదు"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"ఆటోమేటిక్ ఆప్షన్లు వేటినీ సెట్ చేయలేదు"</string>
<string name="tts_settings" msgid="8130616705989351312">"వచనం నుండి ప్రసంగం సెట్టింగ్లు"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"వచనం నుండి మాట అవుట్పుట్"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"ప్రసంగం రేట్"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్లెస్ ప్రదర్శన సర్టిఫికెట్ కోసం ఎంపికలను చూపు"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"బ్యాటరీ శక్తి వినియోగాన్ని తగ్గించి & నెట్వర్క్ పనితీరును మెరుగుపరుస్తుంది"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ఈ మోడ్ ఎనేబుల్ అయ్యాక, MAC ర్యాండమైజేషన్ను ఎనేబుల్ చేసిన నెట్వర్క్తో కనెక్ట్ అయ్యే ప్రతిసారీ ఈ పరికరం MAC అడ్రస్ మారవచ్చు."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"గణించబడుతోంది"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"గణించబడటం లేదు"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"లాగర్ బఫర్ పరిమాణాలు"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"అతిథిని జోడించండి"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"అతిథిని తీసివేయండి"</string>
<string name="guest_nickname" msgid="6332276931583337261">"అతిథి"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 2e809c2..0e958e9 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -205,7 +205,7 @@
<string name="apn_settings_not_available" msgid="1147111671403342300">"การตั้งค่าจุดเข้าใช้งานไม่สามารถใช้ได้สำหรับผู้ใช้รายนี้"</string>
<string name="enable_adb" msgid="8072776357237289039">"การแก้ไขข้อบกพร่อง USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"โหมดแก้ไขข้อบกพร่องเมื่อเชื่อมต่อ USB"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"ยกเลิกการให้สิทธิ์การแก้ปัญหา USB"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"เพิกถอนการให้สิทธิ์การแก้ไขข้อบกพร่อง USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"การแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"โหมดแก้ไขข้อบกพร่องเมื่อเชื่อมต่อ Wi-Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"ข้อผิดพลาด"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์นี้อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายที่มีการเปิดใช้การสุ่ม MAC"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"มีการวัดปริมาณอินเทอร์เน็ต"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
@@ -360,7 +359,7 @@
<string name="track_frame_time" msgid="522674651937771106">"การแสดงผล HWUI ตามโปรไฟล์"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"เปิดใช้เลเยอร์การแก้ไขข้อบกพร่อง GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"อนุญาตให้โหลดเลเยอร์การแก้ไขข้อบกพร่อง GPU สำหรับแอปแก้ไขข้อบกพร่อง"</string>
- <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"เปิดบันทึกเวนเดอร์เพิ่มเติม"</string>
+ <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"เปิดการบันทึกเวนเดอร์แบบละเอียด"</string>
<string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"รวมบันทึกเวนเดอร์เพิ่มเติมเฉพาะอุปกรณ์ไว้ในรายงานข้อบกพร่อง ซึ่งอาจมีข้อมูลส่วนตัว ใช้แบตเตอรี่มากขึ้น และ/หรือใช้พื้นที่เก็บข้อมูลมากขึ้น"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"อัตราการเคลื่อนไหวของหน้าต่าง"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"อัตราการเคลื่อนไหวของการเปลี่ยนภาพ"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้เข้าร่วม"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้เข้าร่วมออก"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ค่าเริ่มต้นของอุปกรณ์"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ปิดใช้"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 69b94ef..5ce89eb 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Binabawasan ang pagkaubos ng baterya at pinapahusay ang performance ng network"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kapag naka-enable ang mode na ito, puwedeng magbago ang MAC address ng device na ito sa tuwing kokonekta ito sa isang network na may naka-enable na MAC randomization."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Nakametro"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Hindi Nakametro"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Mga laki ng buffer ng Logger"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Default ng device"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Naka-disable"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 6c71420..1e887d1 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -428,10 +428,10 @@
<string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Kullanımınıza dayalı olarak yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<!-- no translation found for power_remaining_duration_only_short (7438846066602840588) -->
<skip />
- <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Kullanımınıza göre saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Kullanımınıza göre saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir"</string>
- <string name="power_discharge_by" msgid="4113180890060388350">"Saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_discharge_by_only" msgid="92545648425937000">"Saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir"</string>
+ <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Kullanımınıza göre pilin <xliff:g id="TIME">%1$s</xliff:g> civarına kadar yeteceği tahmin ediliyor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Kullanımınıza göre pilin <xliff:g id="TIME">%1$s</xliff:g> civarına kadar yeteceği tahmin ediliyor"</string>
+ <string name="power_discharge_by" msgid="4113180890060388350">"Pilin <xliff:g id="TIME">%1$s</xliff:g> civarına kadar yeteceği tahmin ediliyor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_discharge_by_only" msgid="92545648425937000">"Pilin <xliff:g id="TIME">%1$s</xliff:g> civarına kadar yeteceği tahmin ediliyor"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"Şu saate kadar: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Pilin tahmini bitiş zamanı: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"En çok <xliff:g id="THRESHOLD">%1$s</xliff:g> kaldı"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Misafir"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cihaz varsayılanı"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Devre dışı"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazının yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 174f6fa..a95105b 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -551,4 +551,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гість"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Пристрій за умовчанням"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Вимкнено"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, перезапустіть пристрій. Перезапустіть пристрій або скасуйте зміни."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 4ad4ddb..463c161 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"بیٹری ڈرین کم کرتا ہے اور نیٹ ورک کارکردگی کو بہتر بناتا ہے"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"جب یہ وضع فعال ہوتا ہے تو، اس آلہ کا MAC پتہ ہر بار تبدیل ہو سکتا ہے جب یہ کسی نیٹ ورک سے منسلک ہوتا ہے جس میں MAC ہے رینڈمائزیشن کو فعال کرتا ہے۔"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"میٹرڈ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"غیر میٹر شدہ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"لاگر بفر کے سائز"</string>
@@ -550,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string>
<string name="guest_nickname" msgid="6332276931583337261">"مہمان"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 80f4157..762a246 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -148,12 +148,12 @@
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth modem"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Modem"</string>
<string name="tether_settings_title_all" msgid="8910259483383010470">"Modem rejimi"</string>
- <string name="managed_user_title" msgid="449081789742645723">"Barcha ishchi ilovalar"</string>
+ <string name="managed_user_title" msgid="449081789742645723">"Barcha ishga oid ilovalar"</string>
<string name="user_guest" msgid="6939192779649870792">"Mehmon"</string>
<string name="unknown" msgid="3544487229740637809">"Noma’lum"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Foydalanuvchi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Ba’zi birlamchi sozlamalar o‘rnatilgan"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"Birlamchi sozlamalar o‘rnatilmagan"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"Birlamchi sozlamalar belgilanmagan"</string>
<string name="tts_settings" msgid="8130616705989351312">"Nutq sintezi sozlamalari"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Nutq sintezi"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Nutq tezligi"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya sarfini tejaydi va tarmoq samaradorligini oshiradi"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyatli tarmoqqa har safar ulanganda almashishi mumkin."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyati mavjud tarmoqqa har safar ulanganda almashishi mumkin."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Trafik hisoblanadigan tarmoq"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Trafik hisobi yuritilmaydigan tarmoq"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi hajmi"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Mehmon rejimini olib tashlash"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Qurilma standarti"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Yoqilmagan"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar qurilma oʻchib yonganda bajariladi. Hoziroq oʻchib yoqish yoki bekor qilish."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index fcfbb02..12241f1 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -205,9 +205,9 @@
<string name="apn_settings_not_available" msgid="1147111671403342300">"Cài đặt tên điểm truy cập không khả dụng cho người dùng này"</string>
<string name="enable_adb" msgid="8072776357237289039">"Gỡ lỗi qua USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"Bật chế độ gỡ lỗi khi kết nối USB"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"Thu hồi ủy quyền gỡ lỗi USB"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"Thu hồi các lượt ủy quyền gỡ lỗi qua USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Gỡ lỗi qua Wi-Fi"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Chế độ gỡ lỗi khi có kết nối Wi-Fi"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Bật chế độ gỡ lỗi khi có kết nối Wi-Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Lỗi"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Gỡ lỗi qua Wi-Fi"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Để xem và sử dụng các thiết bị có sẵn, hãy bật tính năng gỡ lỗi qua Wi-Fi"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Giảm hao pin và cải thiện hiệu suất mạng"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Khi bật chế độ này, địa chỉ MAC của thiết bị này có thể thay đổi mỗi lần thiết bị kết nối với mạng đã bật tính năng sử dụng địa chỉ MAC ngẫu nhiên."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Đo lượng dữ liệu"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Không đo lượng dữ liệu"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Kích thước bộ đệm của trình ghi nhật ký"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Khách"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cài đặt mặc định của thiết bị"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Đã tắt"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 3016f65..05b1b70 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"正在连接到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
<item msgid="3028983857109369308">"正在通过 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 进行身份验证..."</item>
<item msgid="4287401332778341890">"正在从<xliff:g id="NETWORK_NAME">%1$s</xliff:g>获取IP地址..."</item>
- <item msgid="1043944043827424501">"已连接到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+ <item msgid="1043944043827424501">"已连接到“<xliff:g id="NETWORK_NAME">%1$s</xliff:g>”"</item>
<item msgid="7445993821842009653">"已暂停"</item>
<item msgid="1175040558087735707">"正在断开与 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 的连接..."</item>
<item msgid="699832486578171722">"已断开连接"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 58d12af..0a3ca12 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -225,7 +225,7 @@
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"与设备配对"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"WLAN 配对码"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"配对失败"</string>
- <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"确保设备已连接到同一网络。"</string>
+ <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"请确保设备已连接到同一网络。"</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"扫描二维码即可通过 WLAN 配对设备"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"正在配对设备…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"无法配对设备。可能是因为二维码不正确,或者设备未连接到同一网络。"</string>
@@ -284,8 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"显示无线显示认证选项"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"提升 WLAN 日志记录级别(在 WLAN 选择器中显示每个 SSID 的 RSSI)"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗电量以及改善网络性能"</string>
- <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
- <skip />
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"启用此模式后,每当此设备连接到已启用随机分配 MAC 地址功能的网络时,它的 MAC 地址就可能会发生更改。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"按流量计费"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"不按流量计费"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"日志记录器缓冲区大小"</string>
@@ -550,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"访客"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"设备默认设置"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 3396993..495cc22 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -23,7 +23,7 @@
<string name="wifi_fail_to_scan" msgid="2333336097603822490">"無法掃瞄網絡"</string>
<string name="wifi_security_none" msgid="7392696451280611452">"無"</string>
<string name="wifi_remembered" msgid="3266709779723179188">"已儲存"</string>
- <string name="wifi_disconnected" msgid="7054450256284661757">"已解除連接"</string>
+ <string name="wifi_disconnected" msgid="7054450256284661757">"已中斷連線"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"已停用"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"IP 設定失敗"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"網絡品質欠佳,因此無法連線"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"減低耗電量並改善網絡表現"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"啟用這個模式後,每次連線到啟用了 MAC 隨機化的網路時,這部裝置的 MAC 位址都可能會有所變更。"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"啟用此模式後,每次連接至已啟用 MAC 隨機處理的網絡時,此裝置的 MAC 位址都可能會變更。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"按用量收費"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"不限數據用量收費"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"裝置預設設定"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"您的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index dfebe81..9445268 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"裝置預設設定"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 45cd737..86698f4 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -549,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Idivayisi ezenzakalelayo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ikhutshaziwe"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 7b589370..d59d698 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -633,4 +633,18 @@
<item>@color/bt_color_bg_7</item>
</integer-array>
+ <!-- Cached apps freezer modes -->
+ <array name="cached_apps_freezer_entries">
+ <item>@string/cached_apps_freezer_device_default</item>
+ <item>@string/cached_apps_freezer_enabled</item>
+ <item>@string/cached_apps_freezer_disabled</item>
+ </array>
+
+ <!-- Values for cached apps freezer modes -->
+ <array name="cached_apps_freezer_values">
+ <item>device_default</item>
+ <item>enabled</item>
+ <item>disabled</item>
+ </array>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7ca0e80..e42e438 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1365,4 +1365,15 @@
<!-- Name for the guest user [CHAR LIMIT=35] -->
<string name="guest_nickname">Guest</string>
+ <!-- List entry in developer settings to choose default device/system behavior for the app freezer [CHAR LIMIT=30]-->
+ <string name="cached_apps_freezer_device_default">Device default</string>
+ <!-- List entry in developer settings to disable the app freezer in developer settings [CHAR LIMIT=30]-->
+ <string name="cached_apps_freezer_disabled">Disabled</string>
+ <!-- List entry in developer settings to enable the app freezer in developer settings [CHAR LIMIT=30]-->
+ <string name="cached_apps_freezer_enabled">Enabled</string>
+ <!-- Developer setting dialog prompting the user to reboot after changing the app freezer setting [CHAR LIMIT=NONE]-->
+ <string name="cached_apps_freezer_reboot_dialog_text">Your device must be rebooted for this change to apply. Reboot now or cancel.</string>
+
+ <!-- A content description for work profile app [CHAR LIMIT=35] -->
+ <string name="accessibility_work_profile_app_description">Work <xliff:g id="app_name" example="Camera">%s</xliff:g></string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index c4ff719..b1f2a39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -26,6 +26,7 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.R;
@@ -129,7 +130,7 @@
*/
public static boolean isHiddenSystemModule(Context context, String packageName) {
return ApplicationsState.getInstance((Application) context.getApplicationContext())
- .isHiddenModule(packageName);
+ .isHiddenModule(packageName);
}
/**
@@ -140,4 +141,28 @@
.isSystemModule(packageName);
}
+ /**
+ * Returns a boolean indicating whether a given package is a mainline module.
+ */
+ public static boolean isMainlineModule(Context context, String packageName) {
+ final PackageManager pm = context.getPackageManager();
+ try {
+ return pm.getModuleInfo(packageName, 0 /* flags */) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns a content description of an app name which distinguishes a personal app from a
+ * work app for accessibility purpose.
+ * If the app is in a work profile, then add a "work" prefix to the app name.
+ */
+ public static String getAppContentDescription(Context context, String packageName,
+ int userId) {
+ final CharSequence appLabel = getApplicationLabel(context.getPackageManager(), packageName);
+ return UserManager.get(context).isManagedProfile(userId)
+ ? context.getString(R.string.accessibility_work_profile_app_description, appLabel)
+ : appLabel.toString();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 436f2fa..008a433 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -108,10 +108,8 @@
final List<RoutingSessionInfo> infos = mRouterManager.getActiveSessions();
if (infos.size() > 0) {
final RoutingSessionInfo info = infos.get(0);
- final MediaRouter2Manager.RoutingController controller =
- mRouterManager.getControllerForSession(info);
+ mRouterManager.transfer(info, device.mRouteInfo);
- controller.transferToRoute(device.mRouteInfo);
isConnected = true;
}
return isConnected;
@@ -131,7 +129,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null && info.getSelectableRoutes().contains(device.mRouteInfo.getId())) {
- mRouterManager.getControllerForSession(info).selectRoute(device.mRouteInfo);
+ mRouterManager.selectRoute(info, device.mRouteInfo);
return true;
}
@@ -162,7 +160,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null && info.getSelectedRoutes().contains(device.mRouteInfo.getId())) {
- mRouterManager.getControllerForSession(info).deselectRoute(device.mRouteInfo);
+ mRouterManager.deselectRoute(info, device.mRouteInfo);
return true;
}
@@ -207,8 +205,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null) {
- for (MediaRoute2Info route : mRouterManager.getControllerForSession(info)
- .getSelectableRoutes()) {
+ for (MediaRoute2Info route : mRouterManager.getSelectableRoutes(info)) {
deviceList.add(new InfoMediaDevice(mContext, mRouterManager,
route, mPackageName));
}
@@ -235,8 +232,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null) {
- for (MediaRoute2Info route : mRouterManager.getControllerForSession(info)
- .getSelectedRoutes()) {
+ for (MediaRoute2Info route : mRouterManager.getSelectedRoutes(info)) {
deviceList.add(new InfoMediaDevice(mContext, mRouterManager,
route, mPackageName));
}
@@ -434,7 +430,7 @@
}
@Override
- public void onControlCategoriesChanged(String packageName, List<String> controlCategories) {
+ public void onPreferredFeaturesChanged(String packageName, List<String> preferredFeatures) {
if (TextUtils.equals(mPackageName, packageName)) {
refreshDevices();
}
@@ -479,5 +475,10 @@
public void onRequestFailed(int reason) {
dispatchOnRequestFailed(reason);
}
+
+ @Override
+ public void onSessionUpdated(RoutingSessionInfo sessionInfo) {
+ dispatchDataChanged();
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 31ea5b4..9e8c70f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -25,12 +25,16 @@
import android.util.Log;
import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -62,6 +66,7 @@
}
private final Collection<DeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
+ private final Object mMediaDevicesLock = new Object();
@VisibleForTesting
final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback();
@@ -142,7 +147,14 @@
* @param connectDevice the MediaDevice
*/
public void connectDevice(MediaDevice connectDevice) {
- final MediaDevice device = getMediaDeviceById(mMediaDevices, connectDevice.getId());
+ MediaDevice device = null;
+ synchronized (mMediaDevicesLock) {
+ device = getMediaDeviceById(mMediaDevices, connectDevice.getId());
+ }
+ if (device == null) {
+ Log.w(TAG, "connectDevice() connectDevice not in the list!");
+ return;
+ }
if (device instanceof BluetoothMediaDevice) {
final CachedBluetoothDevice cachedDevice =
((BluetoothMediaDevice) device).getCachedDevice();
@@ -181,15 +193,18 @@
* Start scan connected MediaDevice
*/
public void startScan() {
- mMediaDevices.clear();
+ synchronized (mMediaDevicesLock) {
+ mMediaDevices.clear();
+ }
mInfoMediaManager.registerCallback(mMediaDeviceCallback);
mInfoMediaManager.startScan();
}
void dispatchDeviceListUpdate() {
- Collections.sort(mMediaDevices, COMPARATOR);
+ final List<MediaDevice> mediaDevices = new ArrayList<>(mMediaDevices);
+ Collections.sort(mediaDevices, COMPARATOR);
for (DeviceCallback callback : getCallbacks()) {
- callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices));
+ callback.onDeviceListUpdate(mediaDevices);
}
}
@@ -238,9 +253,11 @@
* @return MediaDevice
*/
public MediaDevice getMediaDeviceById(String id) {
- for (MediaDevice mediaDevice : mMediaDevices) {
- if (TextUtils.equals(mediaDevice.getId(), id)) {
- return mediaDevice;
+ synchronized (mMediaDevicesLock) {
+ for (MediaDevice mediaDevice : mMediaDevices) {
+ if (TextUtils.equals(mediaDevice.getId(), id)) {
+ return mediaDevice;
+ }
}
}
Log.i(TAG, "Unable to find device " + id);
@@ -252,6 +269,7 @@
*
* @return MediaDevice
*/
+ @Nullable
public MediaDevice getCurrentConnectedDevice() {
return mCurrentConnectedDevice;
}
@@ -363,18 +381,29 @@
return mInfoMediaManager.getActiveMediaSession();
}
+ /**
+ * Gets the current package name.
+ *
+ * @return current package name
+ */
+ public String getPackageName() {
+ return mPackageName;
+ }
+
private MediaDevice updateCurrentConnectedDevice() {
- MediaDevice phoneMediaDevice = null;
- for (MediaDevice device : mMediaDevices) {
- if (device instanceof BluetoothMediaDevice) {
- if (isActiveDevice(((BluetoothMediaDevice) device).getCachedDevice())) {
+ synchronized (mMediaDevicesLock) {
+ for (MediaDevice device : mMediaDevices) {
+ if (device instanceof BluetoothMediaDevice) {
+ if (isActiveDevice(((BluetoothMediaDevice) device).getCachedDevice())) {
+ return device;
+ }
+ } else if (device instanceof PhoneMediaDevice) {
return device;
}
- } else if (device instanceof PhoneMediaDevice) {
- phoneMediaDevice = device;
}
}
- return mMediaDevices.contains(phoneMediaDevice) ? phoneMediaDevice : null;
+ Log.w(TAG, "updateCurrentConnectedDevice() can't found current connected device");
+ return null;
}
private boolean isActiveDevice(CachedBluetoothDevice device) {
@@ -389,17 +418,26 @@
class MediaDeviceCallback implements MediaManager.MediaDeviceCallback {
@Override
public void onDeviceAdded(MediaDevice device) {
- if (!mMediaDevices.contains(device)) {
- mMediaDevices.add(device);
+ boolean isAdded = false;
+ synchronized (mMediaDevicesLock) {
+ if (!mMediaDevices.contains(device)) {
+ mMediaDevices.add(device);
+ isAdded = true;
+ }
+ }
+
+ if (isAdded) {
dispatchDeviceListUpdate();
}
}
@Override
public void onDeviceListAdded(List<MediaDevice> devices) {
- mMediaDevices.clear();
- mMediaDevices.addAll(devices);
- mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+ synchronized (mMediaDevicesLock) {
+ mMediaDevices.clear();
+ mMediaDevices.addAll(devices);
+ mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+ }
final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice();
mCurrentConnectedDevice = infoMediaDevice != null
@@ -430,7 +468,8 @@
cachedDeviceManager.findDevice(device);
if (cachedDevice != null) {
if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
- && !cachedDevice.isConnected()) {
+ && !cachedDevice.isConnected()
+ && isA2dpOrHearingAidDevice(cachedDevice)) {
deviceCount++;
cachedBluetoothDeviceList.add(cachedDevice);
if (deviceCount >= MAX_DISCONNECTED_DEVICE_NUM) {
@@ -454,32 +493,53 @@
return new ArrayList<>(mDisconnectedMediaDevices);
}
+ private boolean isA2dpOrHearingAidDevice(CachedBluetoothDevice device) {
+ for (LocalBluetoothProfile profile : device.getConnectableProfiles()) {
+ if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void onDeviceRemoved(MediaDevice device) {
- if (mMediaDevices.contains(device)) {
- mMediaDevices.remove(device);
+ boolean isRemoved = false;
+ synchronized (mMediaDevicesLock) {
+ if (mMediaDevices.contains(device)) {
+ mMediaDevices.remove(device);
+ isRemoved = true;
+ }
+ }
+ if (isRemoved) {
dispatchDeviceListUpdate();
}
}
@Override
public void onDeviceListRemoved(List<MediaDevice> devices) {
- mMediaDevices.removeAll(devices);
+ synchronized (mMediaDevicesLock) {
+ mMediaDevices.removeAll(devices);
+ }
dispatchDeviceListUpdate();
}
@Override
public void onConnectedDeviceChanged(String id) {
- MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
+ MediaDevice connectDevice = null;
+ synchronized (mMediaDevicesLock) {
+ connectDevice = getMediaDeviceById(mMediaDevices, id);
+ }
connectDevice = connectDevice != null
? connectDevice : updateCurrentConnectedDevice();
- if (connectDevice != null) {
- connectDevice.setState(MediaDeviceState.STATE_CONNECTED);
- }
mCurrentConnectedDevice = connectDevice;
- dispatchSelectedDeviceStateChanged(mCurrentConnectedDevice,
- MediaDeviceState.STATE_CONNECTED);
+ if (connectDevice != null) {
+ connectDevice.setState(MediaDeviceState.STATE_CONNECTED);
+
+ dispatchSelectedDeviceStateChanged(mCurrentConnectedDevice,
+ MediaDeviceState.STATE_CONNECTED);
+ }
}
@Override
@@ -489,9 +549,11 @@
@Override
public void onRequestFailed(int reason) {
- for (MediaDevice device : mMediaDevices) {
- if (device.getState() == MediaDeviceState.STATE_CONNECTING) {
- device.setState(MediaDeviceState.STATE_CONNECTING_FAILED);
+ synchronized (mMediaDevicesLock) {
+ for (MediaDevice device : mMediaDevices) {
+ if (device.getState() == MediaDeviceState.STATE_CONNECTING) {
+ device.setState(MediaDeviceState.STATE_CONNECTING_FAILED);
+ }
}
}
dispatchOnRequestFailed(reason);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index f1c0f6b..139a12c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,18 +31,14 @@
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.text.TextUtils;
-import android.util.Log;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
-import com.android.settingslib.R;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -180,7 +176,7 @@
*/
public void requestSetVolume(int volume) {
- mRouterManager.requestSetVolume(mRouteInfo, volume);
+ mRouterManager.setRouteVolume(mRouteInfo, volume);
}
/**
@@ -215,30 +211,6 @@
*
* @return application label.
*/
- public String getClientAppLabel() {
- final String packageName = mRouteInfo.getClientPackageName();
- if (TextUtils.isEmpty(packageName)) {
- Log.d(TAG, "Client package name is empty");
- return mContext.getResources().getString(R.string.unknown);
- }
- try {
- final PackageManager packageManager = mContext.getPackageManager();
- final String appLabel = packageManager.getApplicationLabel(
- packageManager.getApplicationInfo(packageName, 0)).toString();
- if (!TextUtils.isEmpty(appLabel)) {
- return appLabel;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "unable to find " + packageName);
- }
- return mContext.getResources().getString(R.string.unknown);
- }
-
- /**
- * Get application label from MediaDevice.
- *
- * @return application label.
- */
public int getDeviceType() {
return mType;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 42f2542..8ea5ff1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -41,7 +41,10 @@
private static final String TAG = "PhoneMediaDevice";
- public static final String ID = "phone_media_device_id_1";
+ public static final String PHONE_ID = "phone_media_device_id";
+ // For 3.5 mm wired headset
+ public static final String WIRED_HEADSET_ID = "wired_headset_media_device_id";
+ public static final String USB_HEADSET_ID = "usb_headset_media_device_id";
private String mSummary = "";
@@ -109,7 +112,25 @@
@Override
public String getId() {
- return ID;
+ String id;
+ switch (mRouteInfo.getType()) {
+ case TYPE_WIRED_HEADSET:
+ case TYPE_WIRED_HEADPHONES:
+ id = WIRED_HEADSET_ID;
+ break;
+ case TYPE_USB_DEVICE:
+ case TYPE_USB_HEADSET:
+ case TYPE_USB_ACCESSORY:
+ case TYPE_DOCK:
+ case TYPE_HDMI:
+ id = USB_HEADSET_ID;
+ break;
+ case TYPE_BUILTIN_SPEAKER:
+ default:
+ id = PHONE_ID;
+ break;
+ }
+ return id;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index cefe690..8968340 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -83,7 +83,16 @@
* <p>An AccessPoint, which would be more fittingly named "WifiNetwork", is an aggregation of
* {@link ScanResult ScanResults} along with pertinent metadata (e.g. current connection info,
* network scores) required to successfully render the network to the user.
+ *
+ * @deprecated WifiTracker/AccessPoint is no longer supported, and will be removed in a future
+ * release. Clients that need a dynamic list of available wifi networks should migrate to one of the
+ * newer tracker classes,
+ * {@link com.android.wifitrackerlib.WifiPickerTracker},
+ * {@link com.android.wifitrackerlib.SavedNetworkTracker},
+ * {@link com.android.wifitrackerlib.NetworkDetailsTracker},
+ * in conjunction with {@link com.android.wifitrackerlib.WifiEntry} to represent each wifi network.
*/
+@Deprecated
public class AccessPoint implements Comparable<AccessPoint> {
static final String TAG = "SettingsLib.AccessPoint";
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 586c154..d1cd043 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -77,7 +77,16 @@
/**
* Tracks saved or available wifi networks and their state.
+ *
+ * @deprecated WifiTracker/AccessPoint is no longer supported, and will be removed in a future
+ * release. Clients that need a dynamic list of available wifi networks should migrate to one of the
+ * newer tracker classes,
+ * {@link com.android.wifitrackerlib.WifiPickerTracker},
+ * {@link com.android.wifitrackerlib.SavedNetworkTracker},
+ * {@link com.android.wifitrackerlib.NetworkDetailsTracker},
+ * in conjunction with {@link com.android.wifitrackerlib.WifiEntry} to represent each wifi network.
*/
+@Deprecated
public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestroy {
/**
* Default maximum age in millis of cached scored networks in
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 2ed9c7b..734866f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -136,7 +136,7 @@
}
@Test
- public void onControlCategoriesChanged_samePackageName_shouldAddMediaDevice() {
+ public void onPreferredFeaturesChanged_samePackageName_shouldAddMediaDevice() {
final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
routingSessionInfos.add(sessionInfo);
@@ -156,7 +156,7 @@
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
- mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged(TEST_PACKAGE_NAME, null);
+ mInfoMediaManager.mMediaRouterCallback.onPreferredFeaturesChanged(TEST_PACKAGE_NAME, null);
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
@@ -165,8 +165,8 @@
}
@Test
- public void onControlCategoriesChanged_differentPackageName_doNothing() {
- mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged("com.fake.play", null);
+ public void onPreferredFeaturesChanged_differentPackageName_doNothing() {
+ mInfoMediaManager.mMediaRouterCallback.onPreferredFeaturesChanged("com.fake.play", null);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(0);
}
@@ -625,6 +625,15 @@
}
@Test
+ public void onSessionUpdated_shouldDispatchDataChanged() {
+ mInfoMediaManager.registerCallback(mCallback);
+
+ mInfoMediaManager.mMediaRouterCallback.onSessionUpdated(mock(RoutingSessionInfo.class));
+
+ verify(mCallback).onDeviceAttributesChanged();
+ }
+
+ @Test
public void addMediaDevice_verifyDeviceTypeCanCorrespondToMediaDevice() {
final MediaRoute2Info route2Info = mock(MediaRoute2Info.class);
final CachedBluetoothDeviceManager cachedBluetoothDeviceManager =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 77316e9..365a16c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -41,6 +41,7 @@
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
@@ -560,6 +561,10 @@
mLocalMediaManager.mMediaDevices.add(device3);
mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+ final List<LocalBluetoothProfile> profiles = new ArrayList<>();
+ final A2dpProfile a2dpProfile = mock(A2dpProfile.class);
+ profiles.add(a2dpProfile);
+
final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
@@ -571,6 +576,7 @@
when(cachedManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(cachedDevice.isConnected()).thenReturn(false);
+ when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
@@ -634,6 +640,10 @@
mLocalMediaManager.mMediaDevices.add(device3);
mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+ final List<LocalBluetoothProfile> profiles = new ArrayList<>();
+ final A2dpProfile a2dpProfile = mock(A2dpProfile.class);
+ profiles.add(a2dpProfile);
+
final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
final BluetoothDevice bluetoothDevice2 = mock(BluetoothDevice.class);
@@ -662,6 +672,7 @@
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(cachedDevice.isConnected()).thenReturn(false);
when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
+ when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
when(bluetoothDevice.getBluetoothClass()).thenReturn(bluetoothClass);
when(bluetoothClass.getDeviceClass()).thenReturn(AUDIO_VIDEO_HEADPHONES);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 6664870..47d4beb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -29,13 +29,9 @@
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageStats;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
-import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidProfile;
@@ -49,8 +45,6 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -70,8 +64,6 @@
private static final String ROUTER_ID_2 = "RouterId_2";
private static final String ROUTER_ID_3 = "RouterId_3";
private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
- private static final String TEST_PACKAGE_NAME2 = "com.test.playmusic2";
- private static final String TEST_APPLICATION_LABEL = "playmusic";
private final BluetoothClass mHeadreeClass =
new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
private final BluetoothClass mCarkitClass =
@@ -125,10 +117,6 @@
private InfoMediaDevice mInfoMediaDevice3;
private List<MediaDevice> mMediaDevices = new ArrayList<>();
private PhoneMediaDevice mPhoneMediaDevice;
- private ShadowPackageManager mShadowPackageManager;
- private ApplicationInfo mAppInfo;
- private PackageInfo mPackageInfo;
- private PackageStats mPackageStats;
@Before
public void setUp() {
@@ -459,41 +447,6 @@
assertThat(mInfoMediaDevice1.getClientPackageName()).isEqualTo(TEST_PACKAGE_NAME);
}
- private void initPackage() {
- mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
- mAppInfo = new ApplicationInfo();
- mAppInfo.flags = ApplicationInfo.FLAG_INSTALLED;
- mAppInfo.packageName = TEST_PACKAGE_NAME;
- mAppInfo.name = TEST_APPLICATION_LABEL;
- mPackageInfo = new PackageInfo();
- mPackageInfo.packageName = TEST_PACKAGE_NAME;
- mPackageInfo.applicationInfo = mAppInfo;
- mPackageStats = new PackageStats(TEST_PACKAGE_NAME);
- }
-
- @Test
- public void getClientAppLabel_matchedPackageName_returnLabel() {
- initPackage();
- when(mRouteInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
-
- assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(
- mContext.getResources().getString(R.string.unknown));
-
- mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
-
- assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(TEST_APPLICATION_LABEL);
- }
-
- @Test
- public void getClientAppLabel_noMatchedPackageName_returnDefault() {
- initPackage();
- mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
- when(mRouteInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME2);
-
- assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(
- mContext.getResources().getString(R.string.unknown));
- }
-
@Test
public void setState_verifyGetState() {
mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 6f265dd..47f6fe3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -21,6 +21,10 @@
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static com.android.settingslib.media.PhoneMediaDevice.PHONE_ID;
+import static com.android.settingslib.media.PhoneMediaDevice.USB_HEADSET_ID;
+import static com.android.settingslib.media.PhoneMediaDevice.WIRED_HEADSET_ID;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
@@ -108,4 +112,22 @@
assertThat(mPhoneMediaDevice.getName())
.isEqualTo(mContext.getString(R.string.media_transfer_this_device_name));
}
+
+ @Test
+ public void getId_returnCorrectId() {
+ when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
+
+ assertThat(mPhoneMediaDevice.getId())
+ .isEqualTo(WIRED_HEADSET_ID);
+
+ when(mInfo.getType()).thenReturn(TYPE_USB_DEVICE);
+
+ assertThat(mPhoneMediaDevice.getId())
+ .isEqualTo(USB_HEADSET_ID);
+
+ when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
+
+ assertThat(mPhoneMediaDevice.getId())
+ .isEqualTo(PHONE_ID);
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a5dce6d..3d7559b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -376,6 +376,9 @@
Settings.Global.BUGREPORT_IN_POWER_MENU,
GlobalSettingsProto.BUGREPORT_IN_POWER_MENU);
dumpSetting(s, p,
+ Settings.Global.CACHED_APPS_FREEZER_ENABLED,
+ GlobalSettingsProto.CACHED_APPS_FREEZER_ENABLED);
+ dumpSetting(s, p,
Settings.Global.CALL_AUTO_RETRY,
GlobalSettingsProto.CALL_AUTO_RETRY);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index be0a864..e537b76 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -264,6 +264,7 @@
Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
Settings.Global.ENABLE_DISKSTATS_LOGGING,
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+ Settings.Global.ENABLE_RESTRICTED_BUCKET,
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
@@ -587,6 +588,8 @@
Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, // Temporary for R beta
Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
+ Settings.Global.CACHED_APPS_FREEZER_ENABLED,
+ Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 4771c41..b85c771 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -233,6 +233,9 @@
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
<uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
+ <!-- Permission required for CTS test - BatterySaverTest -->
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+
<!-- Permission required for CTS test - UiModeManagerTest -->
<uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
@@ -291,6 +294,12 @@
<uses-permission android:name="android.permission.ACCESS_TV_TUNER" />
<uses-permission android:name="android.permission.TUNER_RESOURCE_ACCESS" />
+ <!-- Permissions required for CTS test - AutoRevokeTest -->
+ <uses-permission android:name="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS" />
+
+ <!-- Permissions needed to test shared libraries -->
+ <uses-permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
@@ -337,22 +346,6 @@
android:excludeFromRecents="true"
android:exported="false" />
- <!--
- The following is used as a no-op/null home activity when
- no other MAIN/HOME activity is present (e.g., in CSI).
- -->
- <activity android:name=".NullHome"
- android:excludeFromRecents="true"
- android:label=""
- android:screenOrientation="nosensor">
- <!-- The priority here is set to be lower than that for Settings -->
- <intent-filter android:priority="-1100">
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.HOME" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
<receiver
android:name=".BugreportRequestedReceiver"
android:permission="android.permission.TRIGGER_SHELL_BUGREPORT">
diff --git a/packages/Shell/res/layout/null_home_finishing_boot.xml b/packages/Shell/res/layout/null_home_finishing_boot.xml
deleted file mode 100644
index 5f9563a..0000000
--- a/packages/Shell/res/layout/null_home_finishing_boot.xml
+++ /dev/null
@@ -1,44 +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
- -->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#80000000"
- android:forceHasOverlappingRendering="false">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="40sp"
- android:textColor="?android:attr/textColorPrimary"
- android:text="@*android:string/android_start_title"/>
- <ProgressBar
- style="@android:style/Widget.Material.ProgressBar.Horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12.75dp"
- android:colorControlActivated="?android:attr/textColorPrimary"
- android:indeterminate="true"/>
- </LinearLayout>
-</FrameLayout>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index b81a904..302971f 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"اختر لمشاركة تقرير الأخطاء بدون لقطة شاشة أو انتظر حتى انتهاء لقطة الشاشة"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"انقر لمشاركة تقرير الأخطاء بدون لقطة شاشة أو انتظر حتى انتهاء لقطة الشاشة"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"انقر لمشاركة تقرير الأخطاء بدون لقطة شاشة أو انتظر حتى انتهاء لقطة الشاشة"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"تحتوي تقارير الأخطاء على بيانات من عدة ملفات سجلات في النظام، بما في ذلك بيانات قد ترى أنها حساسة (مثل بيانات استخدام التطبيقات وبيانات الموقع). ولذلك احرص على عدم مشاركة تقارير الأخطاء إلا مع من تثق به من الأشخاص والتطبيقات."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"تحتوي تقارير الأخطاء على بيانات من عدة ملفات سجلات في النظام، بما قد يشمل بيانات تعتبرها حساسة (مثل بيانات استخدام التطبيقات وبيانات الموقع الجغرافي). ولذلك احرص على عدم مشاركة تقارير الأخطاء إلا مع من تثق به من الأشخاص والتطبيقات."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"عدم الإظهار مرة أخرى"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"تقارير الأخطاء"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"تعذرت قراءة ملف تقرير الخطأ."</string>
diff --git a/packages/Shell/res/values-az/strings.xml b/packages/Shell/res/values-az/strings.xml
index 40800bb..1522f3f 100644
--- a/packages/Shell/res/values-az/strings.xml
+++ b/packages/Shell/res/values-az/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Baq hesabatını skrinşot olmadan paylaşmaq üçün seçin, skrinşotun tamamlanması üçün isə gözləyin"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"baq hesabatınızı skrinşot olmadan paylaşmaq üçün tıklayın, skrinşotun tamamlanması üçün isə gözləyin"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"baq hesabatınızı skrinşot olmadan paylaşmaq üçün tıklayın, skrinşotun tamamlanması üçün isə gözləyin"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Baq raportları sistemin müxtəlif jurnal fayllarından həssas təyin etdiyiniz data (tətbiq istifadəsi və məkan datası kimi) içərir. Baq raportlarını yalnız inandığınız tətbiq və adamlarla paylaşın."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Baq hesabatları sistemin müxtəlif jurnal fayllarından həssas təyin etdiyiniz data (tətbiq istifadəsi və məkan datası kimi) içərir. Baq raportlarını yalnız inandığınız tətbiq və adamlarla paylaşın."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Daha göstərməyin"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Baq hesabat faylı oxunmur"</string>
diff --git a/packages/Shell/res/values-be/strings.xml b/packages/Shell/res/values-be/strings.xml
index bea1c30..ce369c3 100644
--- a/packages/Shell/res/values-be/strings.xml
+++ b/packages/Shell/res/values-be/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Выберыце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Справаздачы пра памылкі ўтрымліваюць даныя з розных файлаў журналаў сістэмы, якія могуць уключаць даныя, што вы лічыце канфідэнцыяльнымі (напрыклад, пра выкарыстанне праграм і даныя аб месцазнаходжанні). Абагульвайце справаздачы пра памылкі толькі з тымі людзьмі і праграмамі, якім вы давяраеце."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Справаздачы пра памылкі ўтрымліваюць інфармацыю з розных файлаў журналаў сістэмы, у тым ліку і канфідэнцыяльную (напрыклад, даныя, якія датычацца выкарыстання праграм і месцазнаходжання прылады). Абагульвайце справаздачы пра памылкі толькі з тымі людзьмі і праграмамі, якім вы давяраеце."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Не паказваць зноў"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Справадзачы пра памылкі"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Немагчыма прачытаць файл справаздачы пра памылкі"</string>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index 7893ab5..ab031a4 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Přejetím můžete zprávu o chybě sdílet bez snímku obrazovky, nebo vyčkejte, než se snímek připraví"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Klepnutím můžete zprávu o chybě sdílet bez snímku obrazovky, nebo vyčkejte, než se snímek připraví"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Klepnutím můžete zprávu o chybě sdílet bez snímku obrazovky, nebo vyčkejte, než se snímek připraví"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Zprávy o chybách obsahují data z různých souborů protokolů systému a mohou zahrnovat data, která považujete za citlivá (například informace o využití aplikací a údaje o poloze).Chybová hlášení sdílejte pouze s lidmi a aplikacemi, kterým důvěřujete."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Zprávy o chybách obsahují data z různých souborů protokolů systému a mohou zahrnovat data, která považujete za citlivá (například informace o využití aplikací a údaje o poloze). Chybová hlášení sdílejte pouze s lidmi a aplikacemi, kterým důvěřujete."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Tuto zprávu příště nezobrazovat"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Zprávy o chybách"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Soubor chybové zprávy nelze načíst"</string>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index d9bf877..c23efc3 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Vælg for at dele din fejlrapport uden et screenshot, eller vent på, at et screenshot er klar"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tryk for at dele din fejlrapport uden et screenshot, eller vent på, at screenshott fuldføres"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tryk for at dele din fejlrapport uden et screenshot, eller vent på, at screenshott fuldføres"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Fejlrapporter indeholder data fra systemets forskellige logfiler, som kan være data, du mener er følsomme, f.eks. appforbrug og placeringsdata. Del kun fejlrapporter med personer og apps, du har tillid til."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Fejlrapporter indeholder data fra systemets forskellige logfiler, og der kan være følsomme data imellem (f.eks. appforbrug og placeringsdata). Del kun fejlrapporter med personer og apps, du har tillid til."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Vis ikke igen"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fejlrapporter"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fejlrapportfilen kunne ikke læses"</string>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index fe5ef9c..223d167 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -30,7 +30,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca para compartir el informe de errores sin captura de pantalla o espera a que se haga la captura."</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, que pueden incluir información confidencial (como los datos de uso de las aplicaciones o los de ubicación). Comparte los informes de errores únicamente con usuarios y aplicaciones en los que confíes."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"No volver a mostrar"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de error"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de errores"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No se ha podido leer el archivo del informe de errores"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"No se han podido añadir los detalles del informe de errores al archivo ZIP"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
diff --git a/packages/Shell/res/values-eu/strings.xml b/packages/Shell/res/values-eu/strings.xml
index 2957dab..5d32cab 100644
--- a/packages/Shell/res/values-eu/strings.xml
+++ b/packages/Shell/res/values-eu/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Hautatu hau akatsen txostena argazkirik gabe partekatzeko edo itxaron pantaila-argazkia atera arte"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Sakatu akatsen txostena argazkirik gabe partekatzeko edo itxaron pantaila-argazkia atera arte"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Sakatu akatsen txostena argazkirik gabe partekatzeko edo itxaron pantaila-argazkia atera arte"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Errore-txostenek sistemaren erregistro-fitxategietako datuak dauzkate eta, haietan, kontuzkotzat jotzen duzun informazioa ager daiteke (adibidez, aplikazioen erabilera eta kokapen-datuak). Errore-txostenak partekatzen badituzu, partekatu soilik pertsona eta aplikazio fidagarriekin."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Errore-txostenek sistemaren erregistro-fitxategietako datuak dauzkate, eta, haietan, kontuzkotzat jotzen duzun informazioa ager daiteke (adibidez, aplikazioen erabilera eta kokapen-datuak). Errore-txostenak partekatzen badituzu, partekatu soilik pertsona eta aplikazio fidagarriekin."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ez erakutsi berriro"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Akatsen txostenak"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ezin izan da irakurri akatsen txostena"</string>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index 6fa6f6e..3933557 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -28,9 +28,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Sélectionner pour partager le rapport de bug sans capture d\'écran ou attendre la fin de la capture"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Appuyer pour partager rapport de bug sans capture d\'écran ou attendre finalisation capture d\'écran"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Appuyer pour partager rapport de bug sans capture d\'écran ou attendre finalisation capture d\'écran"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Les rapports de bug contiennent des données des fichiers journaux du système, y compris des informations que vous considérez sensibles concernant, par exemple, la consommation par application et la localisation. Nous vous recommandons de ne partager ces rapports qu\'avec des personnes et des applications que vous estimez fiables."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Les rapports de bugs contiennent des données des fichiers journaux du système, y compris des informations que vous considérez sensibles concernant, par exemple, la consommation par application et la localisation. Nous vous recommandons de ne partager ces rapports qu\'avec des personnes et des applications que vous estimez fiables."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ne plus afficher"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports d\'erreur"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bugs"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier de rapport de bug."</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Impossible d\'ajouter les détails du rapport de bug au fichier .zip"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
diff --git a/packages/Shell/res/values-gu/strings.xml b/packages/Shell/res/values-gu/strings.xml
index 5c25e93..e98e11b 100644
--- a/packages/Shell/res/values-gu/strings.xml
+++ b/packages/Shell/res/values-gu/strings.xml
@@ -28,9 +28,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"સ્ક્રીનશૉટ વિના કે સ્ક્રીનશૉટ પૂરો થાય ત્યાં સુધી રાહ જોયા વિના બગ રિપોર્ટ શેર કરવાનું પસંદ કરો"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"સ્ક્રીનશૉટ વગર અથવા સ્ક્રીનશૉટ સમાપ્ત થવાની રાહ જોયા વગર તમારી બગ રિપોર્ટ શેર કરવા ટૅપ કરો"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"સ્ક્રીનશૉટ વગર અથવા સ્ક્રીનશૉટ સમાપ્ત થવાની રાહ જોયા વગર તમારી બગ રિપોર્ટ શેર કરવા ટૅપ કરો"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"બગ રિપોર્ટ્સ સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે, જેમાં તે ડેટા શામેલ હોઈ શકે છે જેને તમે સંવેદી ગણો છો (જેમ કે ઍપ્લિકેશન-વપરાશ અને સ્થાન ડેટા). બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે ઍપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"બગ રિપોર્ટ સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે, જેમાં તે ડેટા શામેલ હોઈ શકે છે જેને તમે સંવેદી ગણો છો (જેમ કે ઍપ્લિકેશન-વપરાશ અને સ્થાન ડેટા). બગ રિપોર્ટ ફક્ત તમે વિશ્વાસ કરતા હો તે ઍપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"ફરી બતાવશો નહીં"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ્સ"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"બગ રીપોર્ટ ફાઇલ વાંચી શકાઇ નથી"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"ZIP ફાઇલમાં બગ રિપોર્ટની વિગતો ઉમેરી શકાઈ નથી"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"અનામાંકિત"</string>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index 9cbc09d..4764d17 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Odaberite za dijeljenje izvješća o pogrešci bez snimke zaslona ili pričekajte da se izradi snimka"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite za dijeljenje izvješća o pogrešci bez snimke zaslona ili pričekajte da se izradi snimka"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite za dijeljenje izvješća o pogrešci bez snimke zaslona ili pričekajte da se izradi snimka"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Izvješća o programskim pogreškama sadržavaju podatke iz različitih datoteka zapisnika sustava, što može uključivati podatke koje smatrate osjetljivima (na primjer podatke o upotrebi aplikacije i lokaciji). Izvješća o programskim pogreškama dijelite samo s osobama i aplikacijama koje smatrate pouzdanima."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Izvješća o programskim pogreškama sadržavaju podatke iz različitih datoteka zapisnika sustava, što može uključivati podatke koje smatrate osjetljivim (na primjer podatke o upotrebi aplikacije i lokaciji). Izvješća o programskim pogreškama dijelite samo s osobama i aplikacijama koje smatrate pouzdanim."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ne prikazuj ponovo"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Izvješće o programskoj pogrešci nije pročitano"</string>
diff --git a/packages/Shell/res/values-is/strings.xml b/packages/Shell/res/values-is/strings.xml
index b8c0412..4989e87 100644
--- a/packages/Shell/res/values-is/strings.xml
+++ b/packages/Shell/res/values-is/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Veldu að deila villutilkynningunni án skjámyndar eða hinkraðu þangað til skjámyndin er tilbúin"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Ýttu til að deila villutilkynningunni án skjámyndar eða hinkraðu þangað til skjámyndin er tilbúin"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Ýttu til að deila villutilkynningunni án skjámyndar eða hinkraðu þangað til skjámyndin er tilbúin"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Villutilkynningar innihalda gögn úr ýmsum annálaskrám kerfisins, sem gætu innihaldið upplýsingar sem þú telur viðkvæmar (eins og um notkun forrita og staðsetningarupplýsingar). Deildu villutilkynningum bara með fólki og forritum sem þú treystir."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Villutilkynningar innihalda gögn úr ýmsum annálaskrám kerfisins sem gætu innihaldið upplýsingar sem þú telur viðkvæmar (til dæmis notkun forrita og staðsetningarupplýsingar). Deildu villutilkynningum bara með fólki og forritum sem þú treystir."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ekki sýna þetta aftur"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Villutilkynningar"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ekki var hægt að lesa úr villuskýrslunni"</string>
diff --git a/packages/Shell/res/values-km/strings.xml b/packages/Shell/res/values-km/strings.xml
index ec75687..0ab3b68 100644
--- a/packages/Shell/res/values-km/strings.xml
+++ b/packages/Shell/res/values-km/strings.xml
@@ -28,9 +28,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"ជ្រើសរើសដើម្បីចែករំលែករបាយការណ៍អំពីបញ្ហារបស់អ្នកដោយមិនចាំបាច់មានរូបថតអេក្រង់ ឬរង់ចាំរូបថតអេក្រង់ដើម្បីបញ្ចប់"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នកដោយមិនចាំបាច់មានរូបថតអេក្រង់ ឬរង់ចាំការបញ្ចប់ការថតអេក្រង់"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នកដោយមិនចាំបាច់មានរូបថតអេក្រង់ ឬរង់ចាំការបញ្ចប់ការថតអេក្រង់"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"របាយការណ៍ផ្ទុកទិន្នន័យពីឯកសារកំណត់ហេតុផ្សេងៗរបស់ប្រព័ន្ធ ដែលអាចមានផ្ទុកទិន្នន័យដែលអ្នកចាត់ទុកថាជាទិន្នន័យរសើប (ដូចជាការប្រើប្រាស់កម្មវិធី និងទិន្នន័យទីតាំង)។ ចែករំលែករបាយការណ៍កំហុសជាមួយមនុស្ស និងកម្មវិធីដែលអ្នកជឿជាក់ប៉ុណ្ណោះ។"</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"របាយការណ៍អំពីបញ្ហាផ្ទុកទិន្នន័យពីឯកសារកំណត់ហេតុផ្សេងៗរបស់ប្រព័ន្ធ ដែលអាចរួមបញ្ចូលទិន្នន័យដែលអ្នកចាត់ទុកថាមានលក្ខណៈរសើប (ដូចជាការប្រើប្រាស់កម្មវិធី និងទិន្នន័យទីតាំង)។ ចែករំលែករបាយការណ៍អំពីបញ្ហាជាមួយមនុស្ស និងកម្មវិធីដែលអ្នកជឿជាក់តែប៉ុណ្ណោះ។"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"កុំបង្ហាញម្ដងទៀត"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"រាយការណ៍ពីកំហុស"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"របាយការណ៍អំពីបញ្ហា"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"មិនអាចអានឯកសាររបាយកាណ៍កំហុសបានទេ"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"មិនអាចបន្ថែមព័ត៌មានលម្អិតនៃរបាយការណ៍កំហុសទៅឯកសារ zip បានទេ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"គ្មានឈ្មោះ"</string>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 68d4139..545dfa7 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"스크린샷 없이 버그 신고를 공유하려면 선택하고 그렇지 않으면 스크린샷이 완료될 때까지 기다려 주세요."</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"스크린샷 없이 버그 신고서를 공유하려면 탭하고 그렇지 않으면 스크린샷이 완료될 때까지 기다려 주세요."</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"스크린샷 없이 버그 신고서를 공유하려면 탭하고 그렇지 않으면 스크린샷이 완료될 때까지 기다려 주세요."</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"버그 신고서에는 시스템의 다양한 로그 파일 데이터가 포함되며 여기에는 사용자가 중요하다고 생각하는 데이터(예: 앱 사용 및 위치 데이터)가 포함되었을 수 있습니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"버그 신고서에는 시스템의 다양한 로그 파일 데이터가 포함되며 여기에는 사용자가 민감하다고 생각하는 데이터(예: 앱 사용 및 위치 데이터)가 포함되었을 수 있습니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"다시 표시 안함"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"버그 신고"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"버그 신고 파일을 읽을 수 없습니다."</string>
diff --git a/packages/Shell/res/values-ky/strings.xml b/packages/Shell/res/values-ky/strings.xml
index 2499aba..969e9ed 100644
--- a/packages/Shell/res/values-ky/strings.xml
+++ b/packages/Shell/res/values-ky/strings.xml
@@ -30,7 +30,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Мүчүлүштүктөр тууралуу билдирүүлөрдө тутумдун ар кандай таржымалдарынан алынган дайындар, ошондой эле купуя маалымат камтылышы мүмкүн (мисалы, жайгашкан жер сыяктуу). Мындай билдирүүлөрдү бир гана ишеничтүү адамдар жана колдонмолор менен бөлүшүңүз."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрсөтүлбөсүн"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоолор"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоо"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы zip файлына кошулбай койду"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"аталышы жок"</string>
diff --git a/packages/Shell/res/values-ml/strings.xml b/packages/Shell/res/values-ml/strings.xml
index 5c1842a..78b43bb 100644
--- a/packages/Shell/res/values-ml/strings.xml
+++ b/packages/Shell/res/values-ml/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"സ്ക്രീൻഷോട്ട് കൂടാതെയോ സ്ക്രീൻഷോട്ട് പൂർത്തിയാകുന്നതിന് കാക്കാതെയോ ബഗ് റിപ്പോർട്ട് പങ്കിടുക"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"സ്ക്രീൻഷോട്ട് കൂടാതെയോ സ്ക്രീൻഷോട്ട് പൂർത്തിയാകുന്നതിന് കാക്കാതെയോ നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"സ്ക്രീൻഷോട്ട് കൂടാതെയോ സ്ക്രീൻഷോട്ട് പൂർത്തിയാകുന്നതിന് കാക്കാതെയോ നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"ബഗ് റിപ്പോർട്ടുകളിൽ സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള വിവരങ്ങൾ അടങ്ങിയിരിക്കുന്നു, ഇതിൽ നിങ്ങൾ രഹസ്വസ്വഭാവമുള്ളവയായി പരിഗണിക്കുന്ന വിവരങ്ങളും (ആപ്പ് ഉപയോഗ വിവരങ്ങൾ, ലൊക്കേഷൻ വിവരങ്ങൾ എന്നിവ പോലെ) ഉൾപ്പെടാം. നിങ്ങൾ വിശ്വസിക്കുന്ന ആപ്സിനും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"ബഗ് റിപ്പോർട്ടുകളിൽ സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള വിവരങ്ങൾ അടങ്ങിയിരിക്കുന്നു, ഇതിൽ നിങ്ങൾ രഹസ്യ സ്വഭാവമുള്ളവയായി പരിഗണിക്കുന്ന വിവരങ്ങളും (ആപ്പ് ഉപയോഗ വിവരങ്ങൾ, ലൊക്കേഷൻ വിവരങ്ങൾ എന്നിവ പോലെ) ഉൾപ്പെടാം. നിങ്ങൾ വിശ്വസിക്കുന്ന ആപ്പുകൾക്കും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ബഗ് റിപ്പോർട്ടുകൾ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ബഗ് റിപ്പോർട്ട് ഫയൽ വായിക്കാനായില്ല"</string>
diff --git a/packages/Shell/res/values-ne/strings.xml b/packages/Shell/res/values-ne/strings.xml
index 7cc2e6b..3c58796 100644
--- a/packages/Shell/res/values-ne/strings.xml
+++ b/packages/Shell/res/values-ne/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"तपाईंको बग रिपोर्ट स्क्रिनसट बिना आदान प्रदान गर्नाका लागि चयन गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुने प्रतीक्षा गर्नुहोस्"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"तपाईँको बग रिपोर्टलाई स्क्रिनसट बिना साझेदारी गर्नाका लागि ट्याप गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुन प्रतीक्षा गर्नुहोस्"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"तपाईँको बग रिपोर्टलाई स्क्रिनसट बिना साझेदारी गर्नाका लागि ट्याप गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुन प्रतीक्षा गर्नुहोस्"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"बग रिपोर्टमा प्रणालीका विभिन्न लग फाइलहरूको डेटा हुन्छ। यस रिपोर्टमा (अनुप्रयोगको प्रयोग र स्थानसम्बन्धी डेटा जस्ता) जसमा तपाईंका संवेदनशील डेटा समावेश हुन सक्छ । आफूले विश्वास गर्ने व्यक्ति र अनुप्रयोगहरूसँग मात्र बग रिपोर्ट सेयर गर्नुहोस्।"</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"बग रिपोर्टमा प्रणालीका विभिन्न लग फाइलहरूको डेटा हुन्छ। यस रिपोर्टमा (एपको प्रयोग र स्थानसम्बन्धी डेटा जस्ता) जसमा तपाईंका संवेदनशील डेटा समावेश हुन सक्छ । आफूले विश्वास गर्ने व्यक्ति र अनुप्रयोगहरूसँग मात्र बग रिपोर्ट सेयर गर्नुहोस्।"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"फेरि नदेखाउनुहोस्"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फाइल पढ्न सकिएन"</string>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 00669ea..3868f4a 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -30,7 +30,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tik om je bugrapport te delen zonder screenshot of wacht tot het screenshot is voltooid"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Bugrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, die gegevens kunnen bevatten die je als gevoelig beschouwt (zoals gegevens met betrekking tot app-gebruik en locatie). Deel bugrapporten alleen met mensen en apps die je vertrouwt."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Niet opnieuw weergeven"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Bugrapporten"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bestand met bugrapport kan niet worden gelezen"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Kan details van bugrapport niet toevoegen aan zip-bestand"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
diff --git a/packages/Shell/res/values-pa/strings.xml b/packages/Shell/res/values-pa/strings.xml
index 8894814..d0c2905 100644
--- a/packages/Shell/res/values-pa/strings.xml
+++ b/packages/Shell/res/values-pa/strings.xml
@@ -30,7 +30,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੇ ਬਿਨਾਂ ਆਪਣੀ ਬੱਗ ਰਿਪੋਰਟ ਨੂੰ ਸਾਂਝੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਜਾਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੇ ਪੂਰੇ ਹੋਣ ਦੀ ਉਡੀਕ ਕਰੋ"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"ਬੱਗ ਰਿਪੋਰਟਾਂ ਵਿੱਚ ਸਿਸਟਮ ਦੀਆਂ ਵੱਖ-ਵੱਖ ਲੌਗ ਫ਼ਾਈਲਾਂ ਦਾ ਡਾਟਾ ਸ਼ਾਮਲ ਹੁੰਦਾ ਹੈ, ਜਿਸ ਵਿੱਚ ਉਹ ਡਾਟਾ ਸ਼ਾਮਲ ਹੋ ਸਕਦਾ ਹੈ ਜਿਸ ਨੂੰ ਤੁਸੀਂ ਸੰਵੇਦਨਸ਼ੀਲ ਮੰਨਦੇ ਹੋ (ਜਿਵੇਂ ਕਿ ਐਪ-ਵਰਤੋਂ ਅਤੇ ਟਿਕਾਣਾ ਡਾਟਾ)। ਬੱਗ ਰਿਪੋਰਟਾਂ ਨੂੰ ਸਿਰਫ਼ ਆਪਣੇ ਭਰੋਸੇਯੋਗ ਲੋਕਾਂ ਅਤੇ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਕਰੋ।"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"ਬਗ ਰਿਪੋਰਟਾਂ"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"ਬੱਗ ਰਿਪੋਰਟਾਂ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ਬਗ ਰਿਪੋਰਟ ਫ਼ਾਈਲ ਪੜ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕੀ"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"ਬੱਗ ਰਿਪੋਰਟ ਵੇਰਵਿਆਂ ਨੂੰ ਜ਼ਿਪ ਫ਼ਾਈਲ ਵਿੱਚ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ਬਿਨਾਂ-ਨਾਮ"</string>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 3d11d4d..34013fa 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Selecione para partilhar o relatório de erro sem uma captura de ecrã ou aguarde a conclusão da mesma"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toque para partilhar o relatório de erro sem uma captura de ecrã ou aguarde a conclusão da mesma"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toque para partilhar o relatório de erro sem uma captura de ecrã ou aguarde a conclusão da mesma"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Os relatórios de erros contêm dados de vários ficheiros de registo do sistema, que podem incluir dados que considere confidenciais (tais como dados de utilização de aplicações e de localização). Partilhe os relatórios de erros apenas com aplicações fidedignas e pessoas em quem confia."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Os relatórios de erros contêm dados de vários ficheiros de registo do sistema, que podem incluir dados que considere confidenciais (tais como dados de utilização de apps e de localização). Partilhe os relatórios de erros apenas com apps fidedignas e pessoas em quem confia."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Não mostrar de novo"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de erros"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o ficheiro de relatório de erro"</string>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 61a2467..ecceb55 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Klepnutím zdieľajte hlásenie chyby bez snímky obrazovky alebo počkajte na dokončenie snímky obrazovky"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Klepnutím zdieľajte hlásenie chyby bez snímky obrazovky alebo počkajte na dokončenie snímky obrazovky"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Klepnutím zdieľajte hlásenie chyby bez snímky obrazovky alebo počkajte na dokončenie snímky obrazovky"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Hlásenia chýb obsahujú údaje z rôznych súborov denníkov systému, ktoré môžu zahŕňať údaje považované za citlivé (napr. údaje o využití aplikácie a polohe). Zdieľajte ich preto iba s dôveryhodnými ľuďmi a aplikáciami."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Hlásenia chýb obsahujú údaje z rôznych denníkov systému a môžu zahŕňať údaje, ktoré považujete za citlivé (napríklad údaje o využití aplikácií a polohe). Zdieľajte hlásenia chýb iba s ľuďmi a aplikáciami, ktorým dôverujete."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Nabudúce nezobrazovať"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Súbor s hlásením chyby sa nepodarilo prečítať"</string>
diff --git a/packages/Shell/res/values-te/strings.xml b/packages/Shell/res/values-te/strings.xml
index bb0496a..6050c1f 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"షెల్"</string>
- <string name="bugreport_notification_channel" msgid="2574150205913861141">"బగ్ నివేదికలు"</string>
+ <string name="bugreport_notification_channel" msgid="2574150205913861141">"బగ్ రిపోర్ట్స్"</string>
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ నివేదికకు వివరాలను జోడిస్తోంది"</string>
@@ -28,9 +28,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ నివేదికల్లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేషన్ డేటా వంటి) డేటాతో పాటు సిస్టమ్కు సంబంధించిన విభిన్న లాగ్ ఫైల్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేషన్ డేటా వంటి) డేటాతో పాటు సిస్టమ్కు సంబంధించిన విభిన్న లాగ్ ఫైల్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"మళ్లీ చూపవద్దు"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ నివేదికలు"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ రిపోర్ట్స్"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్ను చదవడం సాధ్యపడలేదు"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"బగ్ నివేదిక వివరాలను జిప్ ఫైల్కు జోడించడం సాధ్యపడలేదు"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"పేరు లేనివి"</string>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 8298d15..ccbea4d 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"選擇以分享錯誤報告 (不包含螢幕擷取畫面),或等待螢幕畫面擷取完成"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"輕按以分享錯誤報告 (不包含螢幕擷圖),或等待螢幕畫面擷取完成"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"輕按以分享錯誤報告 (不包含螢幕擷圖),或等待螢幕畫面擷取完成"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"錯誤報告包含來自系統各個記錄檔案的資料,並可能涉及敏感資料 (例如應用程式使用情況和位置資料)。您只應與信任的人和應用程式分享錯誤報告。"</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"錯誤報告包含來自系統多個記錄檔案的資料,並可能涉及對您而言敏感的資料 (例如應用程式使用情況和位置資料)。您只應與信任的人和應用程式分享錯誤報告。"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"不要再顯示"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"無法讀取錯誤報告檔案"</string>
diff --git a/packages/Shell/src/com/android/shell/NullHome.java b/packages/Shell/src/com/android/shell/NullHome.java
deleted file mode 100644
index bd97561..0000000
--- a/packages/Shell/src/com/android/shell/NullHome.java
+++ /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.shell;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * This covers the fallback case where no launcher is available.
- * Usually Settings.apk has one fallback home activity.
- * Settings.apk, however, is not part of CSI, which needs to be
- * standalone (bootable and testable).
- */
-public class NullHome extends Activity {
- private static final String TAG = "NullHome";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.i(TAG, "onCreate");
- setContentView(R.layout.null_home_finishing_boot);
- }
-
- protected void onDestroy() {
- super.onDestroy();
- Log.i(TAG, "onDestroy");
- }
-}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 61b1e30..055b2be 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -155,6 +155,7 @@
<!-- Screen Recording -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
<!-- Assist -->
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
@@ -259,6 +260,9 @@
<!-- Permission to register process observer -->
<uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER"/>
+ <!-- Restore settings (used by QS) even if they have been modified -->
+ <uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
@@ -682,6 +686,7 @@
</activity>
<activity android:name=".controls.management.ControlsEditingActivity"
+ android:label="@string/controls_menu_edit"
android:theme="@style/Theme.ControlsManagement"
android:excludeFromRecents="true"
android:noHistory="true"
@@ -759,7 +764,8 @@
<provider
android:name="com.android.keyguard.clock.ClockOptionsProvider"
android:authorities="com.android.keyguard.clock"
- android:exported="true"
+ android:enabled="false"
+ android:exported="false"
android:grantUriPermissions="true">
</provider>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index aeedc16..e246917 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -66,14 +66,6 @@
void destroy();
- /**
- * return true if the tile supports detail views, and not
- * only boolean states
- */
- default boolean supportsDetailView() {
- return false;
- }
-
CharSequence getTileLabel();
State getState();
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index aadd201..d89bf6a 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Şifrənizi daxil edin"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Yanlış PIN kod."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Yanlış Kart."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Enerji yığdı"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Enerji yığılıb"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Simsiz şəkildə batareya yığır"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Enerji yığır"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sürətlə enerji yığır"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 3813ddd..38451c7 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduce tu contraseña"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"El código PIN es incorrecto."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Tarjeta no válida."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Cargada"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Cargado"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando sin cables"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rápidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 5b8a255..f5d5bb4 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduce o contrasinal"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Código PIN incorrecto"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"A tarxeta non é válida."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Cargada"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Cargado"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando sen fíos"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 9c00ff7..d62795b 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Masukkan sandi"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Kode PIN salah."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kartu Tidak Valid"</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Terisi"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Terisi penuh"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya secara nirkabel"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan cepat"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index a770297..1e47efa 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Digite sua senha"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Código PIN incorreto."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Carregado"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando sem fio"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index a770297..1e47efa 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Digite sua senha"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Código PIN incorreto."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Carregado"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando sem fio"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 16dc4a8..168158d 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Vnesite geslo"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Napačna koda PIN."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Neveljavna kartica"</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Akumulator napolnjen"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Baterija napolnjena"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • brezžično polnjenje"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • polnjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • hitro polnjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index ec44b61..14973f8 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Fut fjalëkalimin"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Kodi PIN është i pasaktë."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Karta e pavlefshme."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"I ngarkuar"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"I karikuar"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me valë"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me shpejtësi"</string>
diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
index 5eb81a4..800fdcf 100644
--- a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
@@ -34,10 +34,10 @@
<string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="8110939900089863103">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="8509811676952707883">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3051962486994265014">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml
index d43f0a3..b6a9850 100644
--- a/packages/SystemUI/res-product/values-sr/strings.xml
+++ b/packages/SystemUI/res-product/values-sr/strings.xml
@@ -34,10 +34,10 @@
<string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="8110939900089863103">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="8509811676952707883">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3051962486994265014">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
index c3e3a3a..d701d92 100644
--- a/packages/SystemUI/res-product/values-uz/strings.xml
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -36,7 +36,7 @@
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3051962486994265014">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ushbu foydalanuvchi oʻchirib tashlanadi va undagi barcha foydalanuvchi maʼlumotlari ham oʻchib ketadi."</string>
<string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ish profili oʻchirib tashlanadi va undagi barcha profil maʼlumotlari ham oʻchib ketadi."</string>
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ish profili oʻchirib tashlanadi va undagi barcha profil maʼlumotlari ham oʻchib ketadi."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ishchi profil oʻchirib tashlanadi va undagi barcha maʼlumotlar ham oʻchib ketadi."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ish profili oʻchirib tashlanadi va undagi barcha maʼlumotlar ham oʻchib ketadi."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ish profili oʻchirib tashlanadi va undagi barcha maʼlumotlar ham oʻchib ketadi."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailingizdan foydalanib, planshet qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib koʻring."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailngizdan foydalanib, telefon qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib koʻring."</string>
diff --git a/packages/SystemUI/res/anim/media_button_state_list_animator.xml b/packages/SystemUI/res/anim/media_button_state_list_animator.xml
new file mode 100644
index 0000000..62ebbaa
--- /dev/null
+++ b/packages/SystemUI/res/anim/media_button_state_list_animator.xml
@@ -0,0 +1,50 @@
+<?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_pressed="true">
+ <set>
+ <objectAnimator
+ android:interpolator="@interpolator/control_state"
+ android:duration="50"
+ android:propertyName="scaleX"
+ android:valueTo="0.9"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:interpolator="@interpolator/control_state"
+ android:duration="50"
+ android:propertyName="scaleY"
+ android:valueTo="0.9"
+ android:valueType="floatType" />
+ </set>
+ </item>
+ <item>
+ <set>
+ <objectAnimator
+ android:interpolator="@interpolator/control_state"
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:interpolator="@interpolator/control_state"
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml b/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml
index b16d038..3660dc4 100644
--- a/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml
+++ b/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml
@@ -17,6 +17,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_activated="true" android:color="@color/kg_user_switcher_activated_background_color" />
+ <item android:state_activated="true" android_state_enabled="true" android:color="@color/kg_user_switcher_activated_background_color" />
+ <item android:state_pressed="true" android:state_enabled="true" android:color="@color/kg_user_switcher_activated_background_color" />
<item android:color="@android:color/transparent" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
index 947c77b..d895dd0 100644
--- a/packages/SystemUI/res/drawable/control_no_favorites_background.xml
+++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
@@ -16,7 +16,22 @@
* limitations under the License.
*/
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <stroke android:width="1dp" android:color="@*android:color/foreground_material_dark"/>
- <corners android:radius="@dimen/control_corner_radius" />
-</shape>
+<!-- Should be kept in sync with the wallet plugin, as both share a similar
+ design: packages/apps/QuickAccessWallet -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#000000" />
+ <corners android:radius="@dimen/control_corner_radius" />
+ </shape>
+ </item>
+ <item>
+ <shape>
+ <stroke
+ android:width="1dp"
+ android:color="#4DFFFFFF" />
+ <corners android:radius="@dimen/control_corner_radius"/>
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/ic_screen_record_background.xml b/packages/SystemUI/res/drawable/ic_screen_record_background.xml
index 9195305..59eb023 100644
--- a/packages/SystemUI/res/drawable/ic_screen_record_background.xml
+++ b/packages/SystemUI/res/drawable/ic_screen_record_background.xml
@@ -13,13 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:tint="?android:attr/colorError"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M10,0L14,0A10,10 0,0 1,24 10L24,10A10,10 0,0 1,14 20L10,20A10,10 0,0 1,0 10L0,10A10,10 0,0 1,10 0z"
- android:fillColor="@android:color/white"/>
-</vector>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="@color/screenrecord_status_color"
+ android:width="@dimen/screenrecord_status_icon_width"
+ android:height="@dimen/screenrecord_status_icon_height" />
+ <corners android:radius="@dimen/screenrecord_status_icon_bg_radius" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_screenrecord.xml b/packages/SystemUI/res/drawable/ic_screenrecord.xml
index 6d8bd0d..d4f807a 100644
--- a/packages/SystemUI/res/drawable/ic_screenrecord.xml
+++ b/packages/SystemUI/res/drawable/ic_screenrecord.xml
@@ -1,7 +1,7 @@
<!--
- Copyright (C) 2020 The Android Open Source Project
+Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,12 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
<path
- android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
- android:fillColor="#FFFFFFFF"/>
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,16c-2.21,0 -4,-1.79 -4,-4c0,-2.21 1.79,-4 4,-4c2.21,0 4,1.79 4,4C16,14.21 14.21,16 12,16zM11.99,1.99c-2.22,0 -4.26,0.73 -5.92,1.96l1.44,1.44c1.28,-0.87 2.82,-1.39 4.49,-1.39c1.67,0 3.21,0.52 4.5,1.4l1.44,-1.44C16.26,2.72 14.22,1.99 11.99,1.99zM16.48,18.6c-1.28,0.87 -2.82,1.39 -4.49,1.39c-1.66,0 -3.2,-0.52 -4.47,-1.39l-1.44,1.44c1.66,1.22 3.7,1.95 5.91,1.95c2.22,0 4.26,-0.73 5.92,-1.95L16.48,18.6zM5.39,16.49c-0.88,-1.28 -1.4,-2.83 -1.4,-4.5c0,-1.66 0.52,-3.21 1.39,-4.49L3.95,6.07c-1.22,1.66 -1.95,3.7 -1.95,5.92c0,2.22 0.73,4.27 1.96,5.93L5.39,16.49zM20.04,6.08l-1.44,1.44c0.87,1.28 1.39,2.82 1.39,4.47c0,1.66 -0.52,3.2 -1.39,4.49l1.44,1.44c1.22,-1.66 1.96,-3.7 1.96,-5.92C21.99,9.78 21.26,7.73 20.04,6.08z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/qs_media_background.xml b/packages/SystemUI/res/drawable/qs_media_background.xml
index 2821e4c..80db3be 100644
--- a/packages/SystemUI/res/drawable/qs_media_background.xml
+++ b/packages/SystemUI/res/drawable/qs_media_background.xml
@@ -14,13 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/colorBackgroundFloating" />
- <corners
- android:bottomLeftRadius="@dimen/qs_media_corner_radius"
- android:topLeftRadius="@dimen/qs_media_corner_radius"
- android:bottomRightRadius="@dimen/qs_media_corner_radius"
- android:topRightRadius="@dimen/qs_media_corner_radius"
- />
-</shape>
\ No newline at end of file
+<com.android.systemui.media.IlluminationDrawable
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ systemui:rippleMinSize="30dp"
+ systemui:rippleMaxSize="135dp"
+ systemui:highlight="15"
+ systemui:cornerRadius="?android:attr/dialogCornerRadius" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml b/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
index 163015b7..21013c6 100644
--- a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
+++ b/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
@@ -17,6 +17,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient
android:angle="90"
- android:startColor="#1f000000"
+ android:startColor="@color/global_screenshot_background_protection_start"
android:endColor="#00000000"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml
index d89f329..da76c8d 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml
@@ -40,7 +40,7 @@
android:layout_height="wrap_content"
style="@style/TextAppearance.AuthCredential.Description"/>
- <EditText
+ <ImeAwareEditText
android:id="@+id/lockPassword"
android:layout_width="208dp"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout-land/global_screenshot_preview.xml b/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
new file mode 100644
index 0000000..b1f4cb7
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
@@ -0,0 +1,33 @@
+<?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.
+ -->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/global_screenshot_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/global_screenshot_x_scale"
+ android:layout_gravity="center"
+ android:layout_marginStart="@dimen/screenshot_offset_x"
+ android:layout_marginBottom="@dimen/screenshot_offset_y"
+ android:scaleType="fitStart"
+ android:elevation="@dimen/screenshot_preview_elevation"
+ android:visibility="gone"
+ android:background="@drawable/screenshot_rounded_corners"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/screenshot_preview_description"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_container_view.xml b/packages/SystemUI/res/layout/auth_container_view.xml
index 63eccda5..3db01a4 100644
--- a/packages/SystemUI/res/layout/auth_container_view.xml
+++ b/packages/SystemUI/res/layout/auth_container_view.xml
@@ -23,7 +23,6 @@
android:id="@+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:accessibilityLiveRegion="polite"
android:background="@color/biometric_dialog_dim_color"
android:contentDescription="@string/biometric_dialog_empty_space_description"/>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_view.xml b/packages/SystemUI/res/layout/bubble_overflow_view.xml
index 88a05ec..1218fba 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_view.xml
+++ b/packages/SystemUI/res/layout/bubble_overflow_view.xml
@@ -30,12 +30,13 @@
<TextView
android:id="@+id/bubble_view_name"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
- android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="13sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:maxLines="1"
+ android:lines="2"
+ android:ellipsize="end"
android:layout_gravity="center"
android:paddingTop="@dimen/bubble_overflow_text_padding"
android:gravity="center"/>
diff --git a/packages/SystemUI/res/layout/controls_dialog_pin.xml b/packages/SystemUI/res/layout/controls_dialog_pin.xml
index 832c48e..170b32b 100644
--- a/packages/SystemUI/res/layout/controls_dialog_pin.xml
+++ b/packages/SystemUI/res/layout/controls_dialog_pin.xml
@@ -26,6 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
+ android:longClickable="false"
android:inputType="numberPassword" />
<CheckBox
android:id="@+id/controls_pin_use_alpha"
diff --git a/packages/SystemUI/res/layout/controls_icon.xml b/packages/SystemUI/res/layout/controls_icon.xml
index cc46ced..12bc5f6 100644
--- a/packages/SystemUI/res/layout/controls_icon.xml
+++ b/packages/SystemUI/res/layout/controls_icon.xml
@@ -19,8 +19,8 @@
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="28dp"
- android:layout_height="28dp"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
android:scaleType="fitCenter"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp" />
+ android:layout_marginLeft="5dp"
+ android:layout_marginRight="5dp" />
diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml
index 4128230..1b24ee9 100644
--- a/packages/SystemUI/res/layout/controls_no_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_no_favorites.xml
@@ -24,11 +24,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="40dp"
- android:paddingBottom="40dp"
- android:layout_marginLeft="10dp"
- android:layout_marginRight="10dp"
- android:layout_marginTop="@dimen/controls_top_margin"
+ android:paddingVertical="@dimen/controls_setup_vertical_padding"
+ android:layout_marginLeft="@dimen/global_actions_side_margin"
+ android:layout_marginRight="@dimen/global_actions_side_margin"
+ android:layout_marginTop="@dimen/controls_setup_top_margin"
android:background="@drawable/control_no_favorites_background">
<LinearLayout
@@ -37,7 +36,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
- android:paddingBottom="8dp" />
+ android:layout_marginBottom="16dp" />
<TextView
style="@style/TextAppearance.ControlSetup.Title"
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
index 477ec6a..99b9ced 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
@@ -14,57 +14,39 @@
limitations under the License.
-->
-<!-- RelativeLayouts have an issue enforcing minimum heights, so just
- work around this for now with LinearLayouts. -->
-<LinearLayout
+<com.android.systemui.globalactions.GlobalActionsItem
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingTop="@dimen/global_actions_grid_item_vertical_margin"
- android:paddingBottom="@dimen/global_actions_grid_item_vertical_margin"
+ android:layout_height="98dp"
+ android:gravity="bottom|center_horizontal"
+ android:orientation="vertical"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
android:paddingLeft="@dimen/global_actions_grid_item_side_margin"
android:paddingRight="@dimen/global_actions_grid_item_side_margin"
android:layout_marginRight="@dimen/control_base_item_margin"
android:layout_marginLeft="@dimen/control_base_item_margin"
android:stateListAnimator="@anim/control_state_list_animator"
android:background="@drawable/control_background">
- <LinearLayout
- android:layout_width="@dimen/global_actions_grid_item_width"
- android:layout_height="@dimen/global_actions_grid_item_height"
- android:gravity="top|center_horizontal"
- android:orientation="vertical">
<ImageView
android:id="@*android:id/icon"
- android:layout_width="@dimen/global_actions_grid_item_icon_width"
- android:layout_height="@dimen/global_actions_grid_item_icon_height"
- android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:layout_marginBottom="14dp"
android:scaleType="centerInside"
- android:tint="@color/control_default_foreground" />
-
+ android:tint="@color/control_primary_text" />
<TextView
android:id="@*android:id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
+ android:ellipsize="end"
android:marqueeRepeatLimit="marquee_forever"
- android:singleLine="true"
+ android:maxLines="2"
+ android:textSize="12sp"
android:gravity="center"
- android:textSize="12dp"
- android:textColor="@color/control_default_foreground"
+ android:textColor="@color/control_primary_text"
+ android:breakStrategy="high_quality"
+ android:hyphenationFrequency="full"
android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <TextView
- android:visibility="gone"
- android:id="@*android:id/status"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textColor="@color/control_default_foreground"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
-</LinearLayout>
+</com.android.systemui.globalactions.GlobalActionsItem>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index e4e9d29..ab4732d 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -46,8 +46,6 @@
<com.android.systemui.globalactions.MinHeightScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
- android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"
android:orientation="vertical"
android:scrollbars="none"
>
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index de19303..d469e0f 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -22,7 +22,7 @@
android:layout_height="match_parent">
<ImageView
android:id="@+id/global_screenshot_actions_background"
- android:layout_height="@dimen/global_screenshot_bg_protection_height"
+ android:layout_height="@dimen/screenshot_bg_protection_height"
android:layout_width="match_parent"
android:alpha="0.0"
android:src="@drawable/screenshot_actions_background_protection"
@@ -71,21 +71,7 @@
android:elevation="@dimen/screenshot_preview_elevation"
android:background="@drawable/screenshot_rounded_corners"
android:adjustViewBounds="true"/>
- <ImageView
- android:id="@+id/global_screenshot_preview"
- android:layout_width="@dimen/global_screenshot_x_scale"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginStart="@dimen/screenshot_offset_x"
- android:layout_marginBottom="@dimen/screenshot_offset_y"
- android:scaleType="fitEnd"
- android:elevation="@dimen/screenshot_preview_elevation"
- android:visibility="gone"
- android:background="@drawable/screenshot_rounded_corners"
- android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_preview_description"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"/>
+ <include layout="@layout/global_screenshot_preview"/>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
diff --git a/packages/SystemUI/res/layout/global_screenshot_preview.xml b/packages/SystemUI/res/layout/global_screenshot_preview.xml
new file mode 100644
index 0000000..e6295f5
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_screenshot_preview.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2011 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.
+ -->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/global_screenshot_preview"
+ android:layout_width="@dimen/global_screenshot_x_scale"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="@dimen/screenshot_offset_x"
+ android:layout_marginBottom="@dimen/screenshot_offset_y"
+ android:scaleType="fitEnd"
+ android:elevation="@dimen/screenshot_preview_elevation"
+ android:visibility="gone"
+ android:background="@drawable/screenshot_rounded_corners"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/screenshot_preview_description"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_media_header.xml b/packages/SystemUI/res/layout/keyguard_media_header.xml
index de9ef21..a520719 100644
--- a/packages/SystemUI/res/layout/keyguard_media_header.xml
+++ b/packages/SystemUI/res/layout/keyguard_media_header.xml
@@ -45,109 +45,4 @@
android:layout_height="match_parent"
/>
- <!-- Layout for media controls. -->
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/keyguard_media_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center"
- android:padding="16dp"
- >
- <ImageView
- android:id="@+id/album_art"
- android:layout_width="@dimen/qs_media_album_size"
- android:layout_height="@dimen/qs_media_album_size"
- android:layout_marginRight="16dp"
- android:layout_weight="0"
- />
-
- <!-- Media information -->
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- >
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- >
- <com.android.internal.widget.CachingIconView
- android:id="@+id/icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_marginEnd="5dp"
- />
- <TextView
- android:id="@+id/app_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="14sp"
- android:singleLine="true"
- />
- </LinearLayout>
-
- <!-- Song name -->
- <TextView
- android:id="@+id/header_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textSize="18sp"
- android:paddingBottom="6dp"
- android:gravity="center"/>
-
- <!-- Artist name -->
- <TextView
- android:id="@+id/header_artist"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textSize="14sp"
- android:singleLine="true"
- />
- </LinearLayout>
-
- <!-- Controls -->
- <LinearLayout
- android:id="@+id/media_actions"
- android:orientation="horizontal"
- android:layoutDirection="ltr"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center"
- android:layout_gravity="center"
- >
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action0"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action1"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action2"
- />
- </LinearLayout>
- </LinearLayout>
-
</com.android.systemui.statusbar.notification.stack.MediaHeaderView>
diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml
index 149446c..03e7467 100644
--- a/packages/SystemUI/res/layout/media_carousel.xml
+++ b/packages/SystemUI/res/layout/media_carousel.xml
@@ -16,20 +16,22 @@
-->
<!-- Carousel for media controls -->
-<HorizontalScrollView
+<com.android.systemui.media.UnboundHorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="@dimen/qs_media_padding"
android:scrollbars="none"
- android:visibility="gone"
+ android:clipChildren="false"
+ android:clipToPadding="false"
>
<LinearLayout
android:id="@+id/media_carousel"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
>
<!-- QSMediaPlayers will be added here dynamically -->
</LinearLayout>
-</HorizontalScrollView>
+</com.android.systemui.media.UnboundHorizontalScrollView>
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index 2401dfb..a261114 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -144,25 +144,36 @@
android:clipToPadding="false"
android:orientation="vertical">
- <LinearLayout
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/settings_link"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal">
- <ImageView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_info"
- android:tint="?android:attr/textColorPrimary"
- android:layout_marginEnd="8dp"/>
- <TextView
- android:id="@+id/non_configurable_text"
+ android:padding="@dimen/notification_importance_button_padding"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_guts_priority_button_bg"
+ android:orientation="vertical">
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup" />
- </LinearLayout>
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal">
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_info"
+ android:tint="?android:attr/textColorPrimary"
+ android:layout_marginEnd="8dp"/>
+ <TextView
+ android:id="@+id/non_configurable_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup" />
+ </LinearLayout>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
<RelativeLayout
android:id="@+id/bottom_buttons"
diff --git a/packages/SystemUI/res/layout/qqs_media_panel.xml b/packages/SystemUI/res/layout/qqs_media_panel.xml
deleted file mode 100644
index 403b5dc..0000000
--- a/packages/SystemUI/res/layout/qqs_media_panel.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<!-- Layout for QQS media controls -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/qqs_media_controls"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center"
- android:paddingTop="16dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingBottom="12dp"
- android:background="@drawable/qs_media_background"
- >
- <!-- Top line: icon + song name -->
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:gravity="center"
- android:layout_marginBottom="12dp"
- >
- <com.android.internal.widget.CachingIconView
- android:id="@+id/icon"
- android:layout_width="14dp"
- android:layout_height="14dp"
- android:layout_marginEnd="5dp"
- />
- <TextView
- android:id="@+id/header_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:singleLine="true"
- />
- </LinearLayout>
-
- <!-- Bottom section: controls -->
- <LinearLayout
- android:id="@+id/media_actions"
- android:orientation="horizontal"
- android:layoutDirection="ltr"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- >
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action0"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action1"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action2"
- />
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 0c9ce39..ebfd0a0 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -23,7 +23,6 @@
android:layout_height="@dimen/qs_footer_height"
android:layout_marginStart="@dimen/qs_footer_margin"
android:layout_marginEnd="@dimen/qs_footer_margin"
- android:elevation="4dp"
android:background="@android:color/transparent"
android:baselineAligned="false"
android:clickable="false"
@@ -128,13 +127,4 @@
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
</com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
- <View
- android:id="@+id/qs_drag_handle_view"
- android:layout_width="48dp"
- android:layout_height="4dp"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
- android:layout_gravity="center_horizontal|bottom"
- android:background="@drawable/qs_footer_drag_handle" />
-
</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml
index a194569..bf06242 100644
--- a/packages/SystemUI/res/layout/qs_media_panel.xml
+++ b/packages/SystemUI/res/layout/qs_media_panel.xml
@@ -16,236 +16,184 @@
-->
<!-- Layout for media controls inside QSPanel carousel -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/qs_media_controls"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:gravity="center_horizontal|fill_vertical"
- android:paddingTop="@dimen/qs_media_panel_outer_padding"
- android:paddingBottom="@dimen/qs_media_panel_outer_padding"
- android:background="@drawable/qs_media_background"
- >
+ app:layoutDescription="@xml/media_scene">
+
+ <View
+ android:id="@+id/media_background"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:background="@drawable/qs_media_background"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ />
+
+ <FrameLayout
+ android:id="@+id/notification_media_progress_time"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:forceHasOverlappingRendering="false">
+ <!-- width is set to "match_parent" to avoid extra layout calls -->
+ <TextView
+ android:id="@+id/media_elapsed_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textColor="@color/media_primary_text"
+ android:gravity="left"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/media_total_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textColor="@color/media_primary_text"
+ android:gravity="right"
+ android:textSize="14sp" />
+ </FrameLayout>
+
+ <ImageButton
+ android:id="@+id/action0"
+ style="@style/MediaPlayer.Button"
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
+
+ <ImageButton
+ android:id="@+id/action1"
+ style="@style/MediaPlayer.Button"
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
+
+ <ImageButton
+ android:id="@+id/action2"
+ style="@style/MediaPlayer.Button"
+ android:layout_width="52dp"
+ android:layout_height="52dp" />
+
+ <ImageButton
+ android:id="@+id/action3"
+ style="@style/MediaPlayer.Button"
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
+
+ <ImageButton
+ android:id="@+id/action4"
+ style="@style/MediaPlayer.Button"
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
+
+ <!-- Album Art -->
+ <ImageView
+ android:id="@+id/album_art"
+ android:layout_width="@dimen/qs_media_album_size"
+ android:layout_height="@dimen/qs_media_album_size" />
+
+ <!-- Seamless Output Switcher -->
+ <LinearLayout
+ android:id="@+id/media_seamless"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="@*android:drawable/media_seamless_background"
+ android:orientation="horizontal"
+ android:forceHasOverlappingRendering="false"
+ android:paddingLeft="12dp"
+ android:paddingTop="6dp"
+ android:paddingRight="12dp"
+ android:paddingBottom="6dp">
+
+ <ImageView
+ android:id="@+id/media_seamless_image"
+ android:layout_width="@dimen/qs_seamless_icon_size"
+ android:layout_height="@dimen/qs_seamless_icon_size"
+ android:layout_marginRight="8dp"
+ android:tint="@color/media_primary_text"
+ android:src="@*android:drawable/ic_media_seamless" />
+
+ <TextView
+ android:id="@+id/media_seamless_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:singleLine="true"
+ android:text="@*android:string/ext_media_seamless_action"
+ android:textColor="@color/media_primary_text"
+ android:textSize="14sp" />
+ </LinearLayout>
+
+ <!-- Seek Bar -->
+ <SeekBar
+ android:id="@+id/media_progress_bar"
+ style="@android:style/Widget.ProgressBar.Horizontal"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:maxHeight="3dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:thumbTint="@color/media_primary_text"
+ android:progressTint="@color/media_seekbar_progress"
+ android:progressBackgroundTint="@color/media_disabled"
+ android:splitTrack="false" />
+
+ <!-- App name -->
+ <TextView
+ android:id="@+id/app_name"
+ android:textColor="@color/media_primary_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textSize="14sp" />
+
+ <!-- Song name -->
+ <TextView
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:singleLine="true"
+ android:textColor="@color/media_primary_text"
+ android:textSize="18sp" />
+
+ <!-- Artist name -->
+ <TextView
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:singleLine="true"
+ android:textColor="@color/media_primary_text"
+ android:textSize="14sp" />
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:tint="@color/media_primary_text"
+ android:layout_width="16dp"
+ android:layout_height="16dp" />
<!-- Buttons to remove this view when no longer needed -->
<include
layout="@layout/qs_media_panel_options"
- android:visibility="gone"/>
+ android:visibility="gone"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
- <LinearLayout
- android:id="@+id/media_guts"
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/view_width"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <!-- Header section -->
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
- android:paddingStart="@dimen/qs_media_panel_outer_padding"
- android:paddingEnd="16dp"
- >
-
- <ImageView
- android:id="@+id/album_art"
- android:layout_width="@dimen/qs_media_album_size"
- android:layout_height="@dimen/qs_media_album_size"
- android:layout_marginRight="16dp"
- android:layout_weight="0"
- />
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- >
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- >
- <com.android.internal.widget.CachingIconView
- android:id="@+id/icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_marginEnd="5dp"
- />
- <TextView
- android:id="@+id/app_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="14sp"
- android:singleLine="true"
- />
- </LinearLayout>
-
- <!-- Song name -->
- <TextView
- android:id="@+id/header_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textSize="18sp"
- android:paddingBottom="6dp"
- android:gravity="center"/>
-
- <!-- Artist name -->
- <TextView
- android:id="@+id/header_artist"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textSize="14sp"
- android:singleLine="true"
- />
- </LinearLayout>
-
- <!-- Output chip -->
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:visibility="gone"
- android:paddingTop="6dp"
- android:paddingBottom="6dp"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
- android:gravity="center"
- android:id="@+id/media_seamless"
- android:background="@*android:drawable/media_seamless_background"
- android:layout_weight="1"
- android:forceHasOverlappingRendering="false"
- >
- <ImageView
- android:layout_width="@dimen/qs_seamless_icon_size"
- android:layout_height="@dimen/qs_seamless_icon_size"
- android:src="@*android:drawable/ic_media_seamless"
- android:layout_marginRight="8dp"
- android:id="@+id/media_seamless_image"
- />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:text="@*android:string/ext_media_seamless_action"
- android:textSize="14sp"
- android:id="@+id/media_seamless_text"
- android:singleLine="true"
- />
- </LinearLayout>
- </LinearLayout>
-
- <!-- Seek Bar -->
- <SeekBar
- android:id="@+id/media_progress_bar"
- style="@android:style/Widget.ProgressBar.Horizontal"
- android:clickable="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxHeight="3dp"
- android:paddingTop="24dp"
- android:paddingBottom="24dp"
- android:layout_marginBottom="-24dp"
- android:layout_marginTop="-24dp"
- android:splitTrack="false"
- />
-
- <FrameLayout
- android:id="@+id/notification_media_progress_time"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/qs_media_panel_outer_padding"
- android:paddingEnd="@dimen/qs_media_panel_outer_padding"
- android:layout_marginBottom="10dp"
- android:layout_gravity="center"
- >
- <!-- width is set to "match_parent" to avoid extra layout calls -->
- <TextView
- android:id="@+id/media_elapsed_time"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textSize="14sp"
- android:gravity="left"
- />
- <TextView
- android:id="@+id/media_total_time"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:layout_alignParentRight="true"
- android:textSize="14sp"
- android:gravity="right"
- />
- </FrameLayout>
-
- <!-- Controls -->
- <LinearLayout
- android:id="@+id/media_actions"
- android:orientation="horizontal"
- android:layoutDirection="ltr"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/qs_media_panel_outer_padding"
- android:paddingEnd="@dimen/qs_media_panel_outer_padding"
- android:gravity="center"
- >
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action0"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action1"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="52dp"
- android:layout_height="52dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action2"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action3"
- />
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:gravity="center"
- android:visibility="gone"
- android:id="@+id/action4"
- />
- </LinearLayout>
- </LinearLayout>
-</LinearLayout>
+ app:layout_constraintGuide_begin="300dp" />
+</androidx.constraintlayout.motion.widget.MotionLayout>
diff --git a/packages/SystemUI/res/layout/qs_media_panel_options.xml b/packages/SystemUI/res/layout/qs_media_panel_options.xml
index 46655e7..e72c0e8 100644
--- a/packages/SystemUI/res/layout/qs_media_panel_options.xml
+++ b/packages/SystemUI/res/layout/qs_media_panel_options.xml
@@ -36,6 +36,7 @@
android:layout_height="18dp"
android:id="@+id/remove_icon"
android:layout_marginEnd="16dp"
+ android:tint="@color/media_primary_text"
android:src="@drawable/ic_clear"/>
<TextView
android:layout_width="wrap_content"
@@ -43,6 +44,7 @@
android:id="@+id/remove_text"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:singleLine="true"
+ android:textColor="@color/media_primary_text"
android:text="@string/controls_media_close_session" />
</LinearLayout>
<TextView
@@ -54,5 +56,6 @@
android:layout_gravity="end|bottom"
android:gravity="bottom"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
android:text="@string/cancel" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 01dfeb2..cdf8426 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -54,20 +54,32 @@
android:layout_marginTop="@*android:dimen/quick_qs_offset_height"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/qs_footer_height"
android:elevation="4dp"
android:background="@android:color/transparent"
android:focusable="true"
- android:accessibilityTraversalBefore="@android:id/edit"
- />
+ android:accessibilityTraversalBefore="@android:id/edit">
+ <include layout="@layout/qs_footer_impl" />
+ </com.android.systemui.qs.QSPanel>
<include layout="@layout/quick_status_bar_expanded_header" />
- <include layout="@layout/qs_footer_impl" />
-
<include android:id="@+id/qs_detail" layout="@layout/qs_detail" />
<include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
android:visibility="gone" />
+ <FrameLayout
+ android:id="@+id/qs_drag_handle_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:elevation="4dp"
+ android:paddingBottom="5dp">
+ <View
+ android:layout_width="46dp"
+ android:layout_height="3dp"
+ android:background="@drawable/qs_footer_drag_handle" />
+ </FrameLayout>
+
+
</com.android.systemui.qs.QSContainerImpl>
diff --git a/packages/SystemUI/res/layout/qs_tile_detail_text.xml b/packages/SystemUI/res/layout/qs_tile_detail_text.xml
deleted file mode 100644
index bcbf826..0000000
--- a/packages/SystemUI/res/layout/qs_tile_detail_text.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<!-- use 'dp' instead of 'sp' as we do not want the text to increase
- if the user scales the font size -->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|center_horizontal"
- android:text="..."
- android:textSize="16dp"
- android:fontFamily="@*android:string/config_headlineFontFamily"
- android:singleLine="true"
- android:visibility="gone"
- android:paddingBottom="@dimen/qs_tile_detail_padding"
- android:clickable="false"
- android:focusable="false" />
-
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index e99b917..9a7c344 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -20,7 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="@*android:dimen/quick_qs_total_height"
+ android:layout_height="wrap_content"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:background="@android:color/transparent"
android:baselineAligned="false"
@@ -29,6 +29,7 @@
android:clipToPadding="false"
android:paddingTop="0dp"
android:paddingEnd="0dp"
+ android:paddingBottom="10dp"
android:paddingStart="0dp"
android:elevation="4dp" >
@@ -45,8 +46,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/quick_qs_status_icons"
- android:layout_marginStart="@dimen/qs_header_tile_margin_horizontal"
- android:layout_marginEnd="@dimen/qs_header_tile_margin_horizontal"
android:accessibilityTraversalAfter="@+id/date_time_group"
android:accessibilityTraversalBefore="@id/expand_indicator"
android:clipChildren="false"
@@ -54,15 +53,6 @@
android:focusable="true"
android:importantForAccessibility="yes" />
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/qs_detail_header_progress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:alpha="0"
- android:background="@color/qs_detail_progress_track"
- android:src="@drawable/indeterminate_anim"/>
-
<TextView
android:id="@+id/header_debug_info"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index df576d8..fd9936f 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -59,29 +59,16 @@
android:layout_gravity="center"
android:layout_weight="0"
android:layout_marginRight="@dimen/screenrecord_dialog_padding"/>
- <LinearLayout
+ <Spinner
+ android:id="@+id/screen_recording_options"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_weight="1">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:text="@string/screenrecord_audio_label"
- android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
- <TextView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/audio_type"
- android:text="@string/screenrecord_mic_label"
- android:textAppearance="?android:attr/textAppearanceSmall"/>
- </LinearLayout>
+ android:layout_height="48dp"
+ android:prompt="@string/screenrecord_audio_label"/>
<Switch
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_weight="0"
+ android:layout_weight="1"
+ android:layout_gravity="end"
android:id="@+id/screenrecord_audio_switch"/>
</LinearLayout>
@@ -102,7 +89,8 @@
android:id="@+id/screenrecord_taps_switch"
android:text="@string/screenrecord_taps_label"
android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
new file mode 100644
index 0000000..af6f9bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:orientation="vertical"
+ android:padding="10dp"
+ android:layout_weight="1">
+ <TextView
+ android:id="@+id/screen_recording_dialog_source_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"/>
+ <TextView
+ android:id="@+id/screen_recording_dialog_source_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source_selected.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source_selected.xml
new file mode 100644
index 0000000..fabe9e2
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source_selected.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:orientation="vertical"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/screenrecord_audio_label"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"/>
+ <TextView
+ android:id="@+id/screen_recording_dialog_source_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b393d21..4d128ce 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Maak skermkiekie toe"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skermkiekievoorskou"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skermopnemer"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Deurlopende kennisgewing vir \'n skermopnamesessie"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Begin opname?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Terwyl dit opneem, kan die Android-stelsel enige sensitiewe inligting wat op jou skerm sigbaar is of wat op jou toestel gespeel word, vasvang. Dit sluit wagwoorde, betalinginligting, foto\'s, boodskappe en oudio in."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Vee alles uit"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Bestuur"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Geskiedenis"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkomend"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Stil kennisgewings"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Opletkennisgewings"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekke"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Titelloos"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tik om hierdie program te herbegin en maak volskerm oop."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Instellings vir <xliff:g id="APP_NAME">%1$s</xliff:g>-borrels"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Oorloop"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Voeg terug op stapel"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Bestuur"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> meer af"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Die lys met alle kontroles kon nie gelaai word nie."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Voeg by toestelkontroles"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Voeg by gunstelinge"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> het voorgestel dat hierdie kontrole by jou gunstelinge gevoeg word."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Voeg by"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Voorgestel deur <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontroles opgedateer"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN bevat letters of simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifieer <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 195000e..f811dc7 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ቅጽበታዊ ገጽ እይታን አሰናብት"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"የቅጽበታዊ ገጽ ዕይታ ቅድመ-ዕይታ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገጽ ቀረጻን በማሰናዳት ላይ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገጽ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"መቅረጽ ይጀመር?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"እየቀረጹ ሳለ የAndroid ስርዓት በማያ ገጽዎ ላይ የሚታይ ወይም በመሣሪያዎ ላይ የሚጫወት ማንኛውም ሚስጥራዊነት ያለው መረጃን መያዝ ይችላል። ይህ የይለፍ ቃላትን፣ የክፍያ መረጃን፣ ፎቶዎችን፣ መልዕክቶችን እና ኦዲዮን ያካትታል።"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ሁሉንም አጽዳ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ያቀናብሩ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ታሪክ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ገቢ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ጸጥ ያሉ ማሳወቂያዎች"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"የማንቂያ ማሳወቂያዎች"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ውይይቶች"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"ርዕስ የለም"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ይህን መተግበሪያ እንደገና ለማስጀመር መታ ያድርጉ እና ወደ ሙሉ ማያ ገጽ ይሂዱ።"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"ቅንብሮች ለ <xliff:g id="APP_NAME">%1$s</xliff:g> አረፋዎች"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ትርፍ ፍሰት"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ወደ ቁልል መልሰው ያክሉ"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ያቀናብሩ"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ <xliff:g id="APP_NAME">%2$s</xliff:g> እና <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ተጨማሪ"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"የሁሉም መቆጣጠሪያዎች ዝርዝር ሊጫን አልተቻለም።"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ወደ የመሣሪያ መቆጣጠሪያዎች ያክሉ"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ወደ ተወዳጆች አክል"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ይህን ቁጥጥር ወደ ተወዳጆችዎ እንዲታከል ሐሳብ ጠቁሟል።"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"አክል"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"በ<xliff:g id="APP">%s</xliff:g> የተጠቆመ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"መቆጣጠሪያዎች ተዘምነዋል"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ፒን ፊደሎችን ወይም ምልክቶችን ይይዛል"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> አረጋግጥ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 9cc6ec3..749241d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -64,7 +64,7 @@
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"لا يُسمح بتصحيح أخطاء USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تفعيل تصحيح الأخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء اللاسلكي\" على هذه الشبكة؟"</string>
- <string name="wifi_debugging_message" msgid="5461204211731802995">"اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
+ <string name="wifi_debugging_message" msgid="5461204211731802995">"اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"السماح باستخدام هذه الميزة على هذه الشبكة دائمًا"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"سماح"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"غير مسموح باستخدام ميزة \"تصحيح الأخطاء اللاسلكي\""</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"إغلاق لقطة الشاشة"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"معاينة لقطة الشاشة"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"هل تريد بدء التسجيل؟"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"أثناء التسجيل، يمكن أن يسجّل نظام Android أي معلومات حساسة مرئية على شاشتك أو يتم تشغيلها على جهازك. ويشمل ذلك كلمات المرور ومعلومات الدفع والصور والرسائل والمقاطع الصوتية."</string>
@@ -521,6 +522,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"محو الكل"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"إدارة"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"السجلّ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"الإشعارات الواردة"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"الإشعارات الصامتة"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"إشعارات التنبيه"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string>
@@ -1007,6 +1009,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string>
<string name="restart_button_description" msgid="6916116576177456480">"انقر لإعادة تشغيل هذا التطبيق والانتقال إلى وضع ملء الشاشة."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"إعدادات فقاعات المحادثات على <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"القائمة الكاملة"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"إضافة دعم إلى الحزم"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"إدارة"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g> و<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> أيضًا"</string>
@@ -1055,8 +1059,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"تعذّر تحميل قائمة كل عناصر التحكّم."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"غير ذلك"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"إضافة إلى أدوات التحكم بالجهاز"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"إضافة إلى الإعدادات المفضّلة"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"اقترح تطبيق <xliff:g id="APP">%s</xliff:g> إضافة عنصر التحكّم هذا إلى الإعدادات المفضّلة."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"إضافة"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"اقتراح من <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"تم تعديل عناصر التحكّم."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"يشتمل رقم التعريف الشخصي على أحرف أو رموز."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"إثبات ملكية <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 6957e20..92be0fe 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"স্ক্ৰীনশ্বট অগ্ৰাহ্য কৰক"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্ৰীনশ্বটৰ পূৰ্বদৰ্শন"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্ৰীন ৰেকৰ্ডাৰ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রীন ৰেকৰ্ডিঙৰ প্ৰক্ৰিয়াকৰণ হৈ আছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রীণ ৰেকৰ্ডিং ছেশ্বন চলি থকা সময়ত পোৱা জাননী"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ৰেকৰ্ড কৰা আৰম্ভ কৰিবনে?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ৰেকৰ্ড কৰি থাকোঁতে, Android Systemএ আপোনাৰ স্ক্রীনত দৃশ্যমান হোৱা অথবা আপোনাৰ ডিভাইচত প্লে’ হৈ থকা যিকোনো সংবেনদশীল তথ্য কেপচাৰ কৰিব পাৰে। এইটোত পাছৱর্ড, পৰিশোধৰ তথ্য, ফট’, বার্তাসমূহ আৰু অডিঅ’ অন্তর্ভুক্ত হয়।"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"সকলো মচক"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"অন্তৰ্গামী"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"নীৰৱ জাননীসমূহ"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"সতৰ্কতামূলক জাননীসমূহ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string>
@@ -960,7 +962,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"অসুবিধা নিদিব-ক কোনো এপ্ (<xliff:g id="ID_1">%s</xliff:g>)এ অন কৰিলে।"</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"অসুবিধা নিদিব-ক এটা স্বয়ংক্ৰিয় নিয়ম বা এপে অন কৰিলে।"</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> পৰ্যন্ত"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"ৰাখক"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"সলনি কৰক"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"নেপথ্যত চলি থকা এপসমূহ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"বেটাৰি আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে বিশদভাৱে জানিবলৈ টিপক"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
<string name="restart_button_description" msgid="6916116576177456480">"এপ্টো ৰিষ্টাৰ্ট কৰক আৰু পূৰ্ণ স্ক্ৰীণ ব্যৱহাৰ কৰক।"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ bubblesৰ ছেটিংসমূহ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"অভাৰফ্ল’"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ষ্টেকত পুনৰ যোগ দিয়ক"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"পৰিচালনা কৰক"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> আৰু<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টাৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"নিয়ন্ত্ৰণসমূহৰ সম্পূর্ণ সূচীখন ল’ড কৰিব পৰা নগ’ল।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহত যোগ দিয়ক"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"প্ৰিয়সমূহত যোগ কৰক"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>এ এই নিয়ন্ত্ৰণটো আপোনাৰ প্ৰিয়সমূহত যোগ কৰাৰ পৰামৰ্শ দিছে।"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ দিয়ক"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>এ পৰামৰ্শ হিচাপে আগবঢ়োৱা"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"নিয়ন্ত্ৰণসমূহ আপডে\'ট কৰা হৈছে"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিনত বৰ্ণ অথবা প্ৰতীকসমূহ থাকে"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> সত্যাপন কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 2714811..9230d4c 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -76,7 +76,7 @@
<string name="learn_more" msgid="4690632085667273811">"Ətraflı məlumat"</string>
<string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string>
- <string name="global_action_screenshot" msgid="2760267567509131654">"Ekran şəkli"</string>
+ <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ekran şəklini ötürün"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran şəklinə önbaxış"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Yazıcısı"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Yazmağa başlanılsın?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Yazarkən Android Sistemi ekranınızda görünən və ya cihazınızda göstərilən istənilən həssas məlumatı qeydə ala bilər. Buraya parollar, ödəniş məlumatı, fotolar, mesajlar və audio daxildir."</string>
@@ -435,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Tətbiqi dəyişmək üçün yuxarı sürüşdürün"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tətbiqləri cəld dəyişmək üçün sağa çəkin"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"İcmala Keçin"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Dolub"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Enerji yığılıb"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Enerji doldurulur"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> dolana kimi"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Doldurulmur"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hamısını silin"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"İdarə edin"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Tarixçə"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gələn"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Səssiz bildirişlər"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Xəbərdarlıq bildirişləri"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Söhbətlər"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Bu tətbiqi sıfırlayaraq tam ekrana keçmək üçün klikləyin."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> yumrucuqları üçün ayarlar"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Kənara çıxma"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Yenidən dəstəyə əlavə edin"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"İdarə edin"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> və daha <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> qabarcıq"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Bütün nizamlayıcıların siyahısı yüklənmədi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz idarəetmələrinə əlavə edin"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Sevimlilərə əlavə edin"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sevimlilərə əlavə etmək üçün bu nizamlayıcını təklif edib."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Əlavə edin"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tərəfindən təklif edilib"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Nizamlayıcılar güncəlləndi"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN hərflər və ya simvollar ehtiva edir"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index a7491777..b633bb6 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Odbacite snimak ekrana"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Želite da započnete snimanje?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Tokom snimanja Android sistem može da snimi osetljive informacije koje su vidljive na ekranu ili koje se puštaju na uređaju. To obuhvata lozinke, informacije o plaćanju, slike, poruke i zvuk."</string>
@@ -396,7 +397,7 @@
<string name="quick_settings_connected" msgid="3873605509184830379">"Povezan"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Povezano, nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"Povezuje se..."</string>
- <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Povezivanje"</string>
+ <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Privezivanje"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Uključuje se..."</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ušteda podataka je uključena"</string>
@@ -512,6 +513,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Nečujna obaveštenja"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Obaveštenja koja privlače pažnju"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzacije"</string>
@@ -992,6 +994,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dodirnite da biste restartovali aplikaciju i prešli u režim celog ekrana."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Podešavanja za <xliff:g id="APP_NAME">%1$s</xliff:g> oblačiće"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Preklapanje"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj ponovo u grupu"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljajte"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1011,10 +1015,10 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigacija sistema je ažurirana. Da biste uneli izmene, idite u Podešavanja."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Prikazuju se u vrhu odeljka za konverzacije"</string>
- <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Prikazuju sliku profila na zaključanom ekranu"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Prikazuje se u vrhu odeljka za konverzacije"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Prikazuje sliku profila na zaključanom ekranu"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Prikazuju se plutajući oblačići preko aplikacija"</string>
- <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ometaju podešavanje Ne uznemiravaj"</string>
+ <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ometa podešavanje Ne uznemiravaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Važi"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećanje"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string>
@@ -1037,8 +1041,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspelo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodajte u omiljene"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> predlaže da dodate ovu kontrolu u omiljene."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifikujte: <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 6de1736..df9a660 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Адхіліць здымак экрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Перадпрагляд здымка экрана"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Пачаць запіс?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Падчас запісу сістэма Android можа збіраць канфідэнцыяльную інфармацыю, якая адлюстроўваецца на экране вашай прылады ці прайграецца на ёй. Гэта могуць быць паролі, плацежная інфармацыя, фота, паведамленні і аўдыяданыя."</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Ачысціць усё"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Кіраваць"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Гісторыя"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Уваходныя"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Апавяшчэнні без гуку"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Апавяшчэнні з абвесткамі"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Размовы"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Націсніце, каб перазапусціць гэту праграму і перайсці ў поўнаэкранны рэжым."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налады ўсплывальных апавяшчэнняў у праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Дадатковае меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Зноў дадаць у стос"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Кіраваць"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" і яшчэ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не ўдалося загрузіць спіс усіх сродкаў кіравання."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Дадаць у элементы кіравання прыладай"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Дадаць у абраныя"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> прапануе дадаць гэты элемент кіравання ў вашы абраныя."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Дадаць"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Прапанавана праграмай \"<xliff:g id="APP">%s</xliff:g>\""</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы кіравання абноўлены"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код складаецца з літар або знакаў"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Спраўдзіце прыладу \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 156fb0f..31e47da 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Разрешаване"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Отстраняването на грешки през USB не е разрешено"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Потребителят, който понастоящем е влязъл в това устройство, не може да включи функцията за отстраняване на грешки през USB. За да я използвате, превключете към основния потребител."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Искате ли да разрешите безжичното отстраняване на грешки в тази мрежа?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Разрешаване на безжичното отстраняване на грешки?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Име на мрежата (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрес на Wi‑Fi мрежата (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Винаги да се разрешава в тази мрежа"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Разрешаване"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Отхвърляне на екранната снимка"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Визуализация на екранната снимка"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Да се стартира ли записът?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"По време на записване системата Android може да прихване поверителна информация, която е показана на екрана или възпроизвеждана на устройството ви. Това включва пароли, данни за плащане, снимки, съобщения и аудио."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Управление"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Входящи"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Беззвучни известия"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Известия за сигнализиране"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Няма заглавие"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Докоснете, за да рестартирате това приложение в режим на цял екран."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Настройки за балончетата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Препълване"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Добавяне обратно към стека"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Управление"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ от<xliff:g id="APP_NAME">%2$s</xliff:g> и още <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Списъкът с всички контроли не бе зареден."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Добавяне към контролите за устройството"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Добавяне в любимите"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> предложи тази контрола да се добави към любимите ви."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавяне"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Предложено от <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите са актуализирани"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН кодът съдържа букви или символи"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Потвърждаване на <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 599bf63..08826e4 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"স্ক্রিনশট বাতিল করুন"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্রিন রেকর্ডার"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"রেকর্ডিং শুরু করবেন?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"রেকর্ড করার সময়, আপনার স্ক্রিনে দেখানো বা ডিভাইসে চালানো যেকোনও ধরনের সংবেদনশীল তথ্য Android সিস্টেম ক্যাপচার করতে পারে। এর মধ্যে পাসওয়ার্ড, পেমেন্টের তথ্য, ফটো, মেসেজ এবং অডিও সম্পর্কিত তথ্য থাকে।"</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"বাবল বাতিল করা হয়েছে।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"বিজ্ঞপ্তি শেড৷"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"দ্রুত সেটিংস৷"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"লক স্ক্রিন।"</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"সবকিছু সাফ করুন"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"পরিচালনা করুন"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ইনকামিং"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"নীরব বিজ্ঞপ্তি"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"বিজ্ঞপ্তি সংক্রান্ত সতর্কতা"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"কথোপকথন"</string>
@@ -961,12 +962,12 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"বিরক্ত করবে না বিকল্পটি একটি অ্যাপ <xliff:g id="ID_1">%s</xliff:g> এর দ্বারা চালু করা হয়েছে।"</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"বিরক্ত করবে না বিকল্পটি একটি স্বয়ংক্রিয় নিয়ম বা অ্যাপের দ্বারা চালু করা হয়েছে।"</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> পর্যন্ত"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"রাখুন"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"বদলে দিন"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"পটভূমিতে অ্যাপ চালু আছে"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ব্যাটারি এবং ডেটার ব্যবহারের বিশদ বিবরণের জন্য ট্যাপ করুন"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"মোবাইল ডেটা বন্ধ করবেন?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"আপনি <xliff:g id="CARRIER">%s</xliff:g>-এর মাধ্যমে ডেটা অথবা ইন্টারনেট অ্যাক্সেস করতে পারবেন না। শুধুমাত্র ওয়াই-ফাইয়ের মাধ্যমেই ইন্টারনেট অ্যাক্সেস করা যাবে।"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"আপনি \'<xliff:g id="CARRIER">%s</xliff:g>\'-এর মাধ্যমে ডেটা অথবা ইন্টারনেট অ্যাক্সেস করতে পারবেন না। শুধুমাত্র ওয়াই-ফাইয়ের মাধ্যমেই ইন্টারনেট অ্যাক্সেস করা যাবে।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"আপনার পরিষেবা প্রদানকারী"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"একটি অ্যাপ কোনও অনুমোদনের অনুরোধকে ঢেকে দিচ্ছে, তাই সেটিংস থেকে আপনার প্রতিক্রিয়া যাচাই করা যাচ্ছে না।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটিকে <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখানোর অনুমতি দেবেন?"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনও শীর্ষক নেই"</string>
<string name="restart_button_description" msgid="6916116576177456480">"এই অ্যাপ রিস্টার্ট করতে ট্যাপ করুন ও ফুল-স্ক্রিন ব্যবহার করুন।"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> বাবলের জন্য সেটিংস"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ওভারফ্লো"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"স্ট্যাকে আবার যোগ করুন"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ম্যানেজ করা"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপ থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপ এবং আরও <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টি থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"যেসব কন্ট্রোল অ্যাক্সেস করতে চান সেগুলি পাওয়ার মেনু থেকে বেছে নিন"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"কন্ট্রোলগুলিকে আবার সাজানোর জন্য ধরে রেখে টেনে আনুন"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"সমস্ত কন্ট্রোল সরানো হয়েছে"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"পরিবর্তন সেভ করা হয়নি"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"সব কন্ট্রোলের তালিকা লোড করা যায়নি।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইস কন্ট্রোলে যোগ করুন"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"পছন্দসইতে যোগ করুন"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"আপনার পছন্দসইতে যোগ করতে <xliff:g id="APP">%s</xliff:g> এই কন্ট্রোল সাজেস্ট করেছে।"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ করুন"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> সাজেস্ট করেছে"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"কন্ট্রোল আপডেট করা হয়েছে"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিন-এ অক্ষর বা চিহ্ন রয়েছে"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> যাচাই করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 6e7722d..28a2930 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -89,9 +89,10 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Odbacite snimak ekrana"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Započeti snimanje?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, Android sistem može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, sistem Android može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimi zvučni zapis"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk uređaja"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk s vašeg uređaja, naprimjer muzika, pozivi i melodije zvona"</string>
@@ -512,6 +513,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Očisti sve"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historija"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Nečujna obavještenja"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Zvučna obavještenja"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
@@ -972,7 +974,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacije koje rade u pozadini"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Dodirnite za detalje o potrošnji baterije i prijenosa podataka"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Isključiti prijenos podataka na mobilnoj mreži?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ili internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi mreže."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ni internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi mreže."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš operater"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
@@ -994,6 +996,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dodirnite da ponovo pokrenete ovu aplikaciju i aktivirate prikaz preko cijelog ekrana."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Postavke za oblačiće aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Preklapanje"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj nazad u grupu"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljaj"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> od aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"Obavještenje <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1039,8 +1043,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspjelo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodajte u omiljeno"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacija <xliff:g id="APP">%s</xliff:g> je predložila da se ova kontrola doda u omiljeno."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bf8c113..15cc8d3 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora la captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Previsualització de la captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Vols iniciar la gravació?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Quan graves contingut, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou les contrasenyes, la informació de pagament, les fotos, els missatges i l\'àudio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Esborra-ho tot"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gestiona"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrants"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificacions silencioses"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificacions d\'alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Converses"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sense títol"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toca per reiniciar l\'aplicació i passar a pantalla completa."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuració de les bombolles: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menú addicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Torna a afegir a la pila"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gestiona"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) i <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> més"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No s\'ha pogut carregar la llista completa de controls."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Afegeix als controls de dispositius"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Afegeix als preferits"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ha suggerit aquest control perquè l\'afegeixis als preferits."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Afegeix"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggerit per <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"S\'han actualitzat els controls"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN conté lletres o símbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8bce8ec..e3d9e384 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zavřít snímek obrazovky"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Náhled snímku obrazovky"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Spustit nahrávání?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Při nahrávání může systém Android zaznamenávat citlivé údaje, které jsou viditelné na obrazovce nebo které jsou přehrávány na zařízení. Týká se to hesel, údajů o platbě, fotek, zpráv a zvuků."</string>
@@ -400,7 +401,7 @@
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"Sdílené připojení"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Zapínání…"</string>
- <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Spořič dat je zapnutý"</string>
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Spořič dat zapnut"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
<item quantity="few">%d zařízení</item>
<item quantity="many">%d zařízení</item>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Smazat vše"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Příchozí"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Tichá oznámení"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Oznámení s upozorněním"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Klepnutím aplikaci restartujete a přejdete na režim celé obrazovky"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Nastavení bublin aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Rozbalovací nabídka"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Přidat zpět do sady"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Spravovat"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"Oznámení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> a dalších (<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Načtení seznamu všech ovládacích prvků se nezdařilo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Přidání ovládání zařízení"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Přidat k oblíbeným"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikace <xliff:g id="APP">%s</xliff:g> navrhuje přidat tento ovládací prvek do oblíbených."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Přidat"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Návrh z aplikace <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládací prvky aktualizovány"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmena nebo symboly"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Ověření zařízení <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1837073..3d244cc6 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Luk screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning af screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptagelse"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Vil du starte optagelse?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Når du optager, kan Android-systemet registrere følsomme oplysninger, der er synlige på din skærm, eller som afspilles på din enhed. Dette inkluderer adgangskoder, betalingsoplysninger, fotos, meddelelser og lyd."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Indgående"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Lydløse notifikationer"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notifikationer med vibration eller lyd"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tryk for at genstarte denne app, og gå til fuld skærm."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Indstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>-bobler"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overløb"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Føj til stak igen"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Administrer"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> andre"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over styringselementer kunne ikke indlæses."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Føj til enhedsstyring"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Føj til favoritter"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> har foreslået, at du føjer denne funktion til dine favoritter."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Tilføj"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Foreslået af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Betjeningselementerne er opdateret"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden indeholder bogstaver eller symboler"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Bekræft <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1f78537..8ef83bd 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Screenshot schließen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Aufzeichnung starten?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Beim Aufnehmen kann das Android-System vertrauliche Informationen erfassen, die auf deinem Bildschirm angezeigt oder von deinem Gerät wiedergegeben werden. Das können Passwörter, Zahlungsinformationen, Fotos, Nachrichten und Audioinhalte sein."</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Benachrichtigung geschlossen"</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble verworfen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Benachrichtigungsleiste"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Schnelleinstellungen"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sperrbildschirm"</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Alle löschen"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Verwalten"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Verlauf"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Neue Benachrichtigungen"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Lautlose Benachrichtigungen"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Laut gestellte Benachrichtigungen"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string>
@@ -712,7 +713,7 @@
<string name="notification_channel_summary_default" msgid="3539949463907902037">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt."</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="6298026344552480458">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt. Unterhaltungen von <xliff:g id="APP_NAME">%1$s</xliff:g> werden standardmäßig als Bubble angezeigt."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Du wirst mit einer unverankerten Verknüpfung darauf aufmerksam gemacht."</string>
- <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Wird oben im Bereich für Unterhaltungen als Bubble angezeigt."</string>
+ <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Wird oben im Bereich \"Unterhaltungen\" als Bubble angezeigt."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Einstellungen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
<string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine unterhaltungsspezifischen Einstellungen"</string>
@@ -818,7 +819,7 @@
<string name="accessibility_long_click_tile" msgid="210472753156768705">"Einstellungen öffnen"</string>
<string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"Mit Kopfhörer verbunden"</string>
<string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Mit Headset verbunden"</string>
- <string name="data_saver" msgid="3484013368530820763">"Datenverbrauch reduzieren"</string>
+ <string name="data_saver" msgid="3484013368530820763">"Datensparmodus"</string>
<string name="accessibility_data_saver_on" msgid="5394743820189757731">"Datensparmodus aktiviert"</string>
<string name="accessibility_data_saver_off" msgid="58339669022107171">"Datensparmodus deaktiviert"</string>
<string name="switch_bar_on" msgid="1770868129120096114">"An"</string>
@@ -851,7 +852,7 @@
<string name="right_keycode" msgid="2480715509844798438">"Rechter Keycode"</string>
<string name="left_icon" msgid="5036278531966897006">"Linkes Symbol"</string>
<string name="right_icon" msgid="1103955040645237425">"Rechtes Symbol"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"Zum Hinzufügen von Kacheln Kachel halten und ziehen"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"Zum Hinzufügen Kachel halten und ziehen"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Zum Verschieben Kachel halten und ziehen"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Zum Entfernen hierher ziehen"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Du brauchst mindestens <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> Kacheln"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Kein Titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tippe, um die App im Vollbildmodus neu zu starten."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Einstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g>-Bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Mehr anzeigen"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Wieder dem Stapel hinzufügen"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Verwalten"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> von <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aus <xliff:g id="APP_NAME">%2$s</xliff:g> und <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> weiteren"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Karten auswählen, auf die man über das Ein-/Aus-Menü zugreifen kann"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Zum Verschieben von Steuerelementen halten und ziehen"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alle Steuerelemente entfernt"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Änderungen nicht gespeichert"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Fehler beim Laden der Liste mit Steuerelementen."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andere"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Zur Gerätesteuerung hinzufügen"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Zu Favoriten hinzufügen"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"\"<xliff:g id="APP">%s</xliff:g>\" hat vorgeschlagen, dieses Steuerelement deinen Favoriten hinzuzufügen."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Hinzufügen"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Vorgeschlagen von <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Gerätekarten aktualisiert"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Die PIN enthält Buchstaben oder Symbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> bestätigen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 16cf78b..1a93009 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Παράβλεψη στιγμιότυπου οθόνης"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Προεπισκόπηση στιγμιότυπου οθόνης"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Εγγραφή οθόνης"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Έναρξη εγγραφής;"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Κατά την εγγραφή, το σύστημα Android μπορεί να καταγράψει τυχόν ευαίσθητες πληροφορίες που είναι ορατές στην οθόνη ή αναπαράγονται στη συσκευή σας. Σε αυτές περιλαμβάνονται οι κωδικοί πρόσβασης, οι πληροφορίες πληρωμής, οι φωτογραφίες, τα μηνύματα και ο ήχος."</string>
@@ -232,7 +233,7 @@
<string name="cell_data_off_content_description" msgid="9165555931499878044">"Τα δεδομένα κινητής τηλεφωνίας απενεργοποιήθηκαν"</string>
<string name="not_default_data_content_description" msgid="6757881730711522517">"Δεν ρυθμίστηκε ώστε να χρησιμοποιεί δεδομένα"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Ανενεργά"</string>
- <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"Πρόσδεση Bluetooth"</string>
+ <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"Σύνδεση με Bluetooth"</string>
<string name="accessibility_airplane_mode" msgid="1899529214045998505">"Λειτουργία πτήσης."</string>
<string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN ενεργό."</string>
<string name="accessibility_no_sims" msgid="5711270400476534667">"Δεν υπάρχει κάρτα SIM."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Διαγραφή όλων"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Διαχείριση"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Ιστορικό"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Εισερχόμενες"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Ειδοποιήσεις σε σίγαση"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Ειδοποιήσεις"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Χωρίς τίτλο"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Πατήστε για επανεκκίνηση αυτής της εφαρμογής και ενεργοποίηση πλήρους οθόνης."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Ρυθμίσεις για συννεφάκια <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Υπερχείλιση"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Προσθήκη ξανά στη στοίβα"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Διαχείριση"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από την εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> και <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ακόμη"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ανεπιτυχής φόρτωση λίστας όλων των στοιχ. ελέγχου."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Προσθήκη στα στοιχεία ελέγχου συσκευής"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Προσθήκη στα αγαπημένα"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> πρότεινε αυτό το στοιχείο ελέγχου για προσθήκη στα αγαπημένα."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Προσθήκη"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Προτείνεται από <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Ενημέρωση στοιχείων ελέγχου"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Το PIN περιέχει γράμματα ή σύμβολα"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Επαλήθευση <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 296d974..b2a03d2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Silent notifications"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Alerting notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 4e85aad..db9ed99 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Silent notifications"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Alerting notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 296d974..b2a03d2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Silent notifications"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Alerting notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 296d974..b2a03d2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Silent notifications"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Alerting notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 69a226c..2b87b82 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start Recording?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages, and audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Silent notifications"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Alerting notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favorites"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favorites."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 966d07a..e7d6878 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -89,8 +89,9 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Descartar captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de la captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Grabadora de pantalla"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
- <string name="screenrecord_start_label" msgid="1750350278888217473">"¿Comenzar grabación?"</string>
+ <string name="screenrecord_start_label" msgid="1750350278888217473">"¿Comenzar a grabar?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Durante la grabación, el sistema de Android puede capturar la información sensible que aparezca en la pantalla o que se reproduzca en el dispositivo. Se incluyen contraseñas, información de pago, fotos, mensajes y audio."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabar audio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio del dispositivo"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrante"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificaciones silenciosas"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificaciones de alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Presiona para reiniciar esta app y acceder al modo de pantalla completa."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuración para burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menú ampliado"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Volver a agregar a la pila"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Administrar"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se cargó la lista completa de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Agregar a controles de dispositivos"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Agregar a favoritos"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"La app <xliff:g id="APP">%s</xliff:g> sugirió que agregaras este control a favoritos."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Agregar"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 1b5c32a..d1f5198 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Cerrar captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"¿Empezar a grabar?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Mientras grabas, el sistema Android puede capturar información sensible que se muestre o se reproduzca en tu dispositivo, como contraseñas, datos de pago, fotos, mensajes y audio."</string>
@@ -398,7 +399,7 @@
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"Compartir conexión"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Zona Wi-Fi"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activando…"</string>
- <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos: sí"</string>
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos activado"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
<item quantity="other">%d dispositivos</item>
<item quantity="one">%d dispositivo</item>
@@ -428,8 +429,8 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"El NFC está desactivado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"El NFC está activado"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabación de la pantalla"</string>
- <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicio"</string>
+ <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabar pantalla"</string>
+ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de aplicación"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificaciones silenciadas"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificaciones de alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
@@ -587,8 +589,8 @@
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Transcripción instantánea"</string>
<string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"Cerrar las recomendaciones de subtítulos"</string>
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
- <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"habilitar"</string>
- <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inhabilitar"</string>
+ <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activar"</string>
+ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Cambiar dispositivo de salida"</string>
<string name="screen_pinning_title" msgid="7357611095909618178">"Pantalla fijada"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toca para reiniciar esta aplicación e ir a la pantalla completa."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Ajustes de las burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menú adicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Volver a añadir a la pila"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gestionar"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string>
@@ -1006,10 +1010,10 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se ha actualizado la navegación del sistema. Para hacer cambios, ve a Ajustes."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Aparecen arriba de la sección de conversaciones"</string>
- <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran imagen de perfil en pantalla de bloqueo"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de la sección de conversaciones"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran tu imagen de perfil en la pantalla de bloqueo"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbuja sobre las aplicaciones"</string>
- <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrumpen No molestar"</string>
+ <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrumpen el modo No molestar"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana de superposición de ampliación"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se ha podido cargar la lista de los controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Añadir a control de dispositivos"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Añadir a favoritos"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"La aplicación <xliff:g id="APP">%s</xliff:g> ha sugerido este control para que lo añadas a tus favoritos."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Añadir"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 4b911a9..c1b4b79 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Sule ekraanipilt"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekraanipildi eelvaade"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Kas alustada salvestamist?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Heli salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Tühjenda kõik"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Haldamine"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Ajalugu"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Sissetulevad"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Hääletud märguanded"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Hoiatusmärguanded"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Vestlused"</string>
@@ -713,7 +715,7 @@
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Hoiab teie tähelepanu hõljuva otseteega selle sisu juurde."</string>
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Kuvatakse vestluste jaotise ülaosas mullina."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Seaded"</string>
- <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteet"</string>
+ <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
<string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestluspõhiseid seadeid"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hiljutisi mulle pole"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Siin kuvatakse hiljutised ja suletud mullid."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Pealkiri puudub"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Puudutage rakenduse taaskäivitamiseks ja täisekraanrežiimi aktiveerimiseks."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> mullide seaded"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Ületäide"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Lisa tagasi virna"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Halda"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> rakendusest <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> rakenduselt <xliff:g id="APP_NAME">%2$s</xliff:g> ja veel <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1009,12 +1013,12 @@
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Kuvatakse vestluste jaotise kohal"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Lukustuskuval kuvatakse profiilipilt"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Kuvatakse rakenduste kohal hõljuva mullina"</string>
- <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Funktsiooni Mitte segada katkestamine"</string>
+ <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Funktsioon Mitte segada katkestatakse"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Selge"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Suurendamisakna ülekate"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurendamisakna juhtelemendid"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhtimisvidinad"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisage juhtelemendid ühendatud seadmete jaoks"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Seadmete juhtimisvidinate seadistamine"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Juhtelementidele juurdepääsemiseks hoidke all toitenuppu"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kõikide juhtelementide loendit ei saanud laadida."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Seadmete juhtimisvidinate hulka lisamine"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Lisa lemmikutesse"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> soovitas selle juhtnupu teie lemmikutesse lisada."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisa"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Soovitas <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Juhtelemente värskendati"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-kood sisaldab tähti või sümboleid"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Kinnitage <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 930d571..944b07b 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -65,7 +65,7 @@
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu USB bidezko arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Hari gabeko arazketa onartu nahi duzu sare honetan?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Sarearen izena (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWifi-helbidea (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
- <string name="wifi_debugging_always" msgid="2968383799517975155">"Onartu beti sare honetan"</string>
+ <string name="wifi_debugging_always" msgid="2968383799517975155">"Baimendu beti sare honetan"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Baimendu"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Ez da onartzen hari gabeko arazketa"</string>
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu hari gabeko arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Baztertu pantaila-argazkia"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pantaila-argazkiaren aurrebista"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Grabatzen hasi nahi duzu?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Pantaila grabatzen duzun bitartean, Android sistemak detektatu egin dezake pantailan agertzen den edo gailuak erreproduzitzen duen kontuzko informazioa; besteak beste, pasahitzak, ordainketen informazioa, argazkiak, mezuak eta audioak."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Garbitu guztiak"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Kudeatu"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Jasotako azkenak"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Soinurik gabeko jakinarazpenak"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Soinua/Dar-dar egiten duten jakinarazpenak"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Elkarrizketak"</string>
@@ -850,8 +852,8 @@
<string name="right_keycode" msgid="2480715509844798438">"Eskuineko teklaren kodea"</string>
<string name="left_icon" msgid="5036278531966897006">"Ezkerreko ikonoa"</string>
<string name="right_icon" msgid="1103955040645237425">"Eskuineko ikonoa"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"Lauzak gehitzeko, eduki sakatuta eta arrastatu"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Lauzak antolatzeko, eduki sakatuta eta arrastatu"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"Lauzak gehitzeko, eduki itzazu sakatuta, eta arrastatu"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Lauzak antolatzeko, eduki itzazu sakatuta, eta arrastatu"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Kentzeko, arrastatu hona"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> lauza behar dituzu gutxienez"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editatu"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Berrabiarazi aplikazio hau eta ezarri pantaila osoko modua."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren ezarpenen burbuilak"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Gainezkatzea"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Gehitu berriro errenkadan"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Kudeatu"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioaren \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" jakinarazpena, eta beste <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ezin izan da kargatu kontrol guztien zerrenda."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Gehitu gailuak kontrolatzeko widgetetan"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Gehitu gogokoetan"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> aplikazioak aukera hau gogokoetan gehitzea iradoki du."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Gehitu"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> aplikazioak iradoki du"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Eguneratu dira kontrolatzeko aukerak"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodeak hizkiak edo ikurrak ditu"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Egiaztatu <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index dab05e2..64b3f8c 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"رد کردن نماگرفت"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"پیشنمایش نماگرفت"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ضبطکننده صفحهنمایش"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحهنمایش"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحهنمایش"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ضبط شروع شود؟"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"هنگام ضبط، «سیستم Android» میتواند هر اطلاعات حساسی را که روی صفحهنمایش شما نشان داده میشود یا روی دستگاه شما پخش میشود ضبط کند. این شامل گذرواژهها، اطلاعات پرداخت، عکسها، پیامها، و صدا میشود."</string>
@@ -194,7 +195,7 @@
<string name="accessibility_data_signal_full" msgid="283507058258113551">"قدرت سیگنال داده کامل است."</string>
<string name="accessibility_wifi_name" msgid="4863440268606851734">"به <xliff:g id="WIFI">%s</xliff:g> متصل شد."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string>
- <string name="accessibility_cast_name" msgid="7344437925388773685">"متصل به <xliff:g id="CAST">%s</xliff:g>."</string>
+ <string name="accessibility_cast_name" msgid="7344437925388773685">"به <xliff:g id="CAST">%s</xliff:g> متصل شد."</string>
<string name="accessibility_no_wimax" msgid="2014864207473859228">"WiMAX وجود ندارد."</string>
<string name="accessibility_wimax_one_bar" msgid="2996915709342221412">"WiMAX یک نوار دارد."</string>
<string name="accessibility_wimax_two_bars" msgid="7335485192390018939">"WiMAX دو نوار دارد."</string>
@@ -509,8 +510,9 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"مدیریت"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"سابقه"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ورودی"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"اعلانهای بیصدا"</string>
- <string name="notification_section_header_alerting" msgid="3168140660646863240">"اعلانهای هشدار"</string>
+ <string name="notification_section_header_alerting" msgid="3168140660646863240">"اعلانهای هشداردهنده"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمهها"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلانهای بیصدا"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلانها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"بدون عنوان"</string>
<string name="restart_button_description" msgid="6916116576177456480">"برای بازراهاندازی این برنامه و تغییر به حالت تمامصفحه، ضربه بزنید."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"تنظیم برای ابزارکهای اعلان <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"لبریزشده"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"افزودن برگشت به پشته"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"مدیریت"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مورد بیشتر"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"فهرست همه کنترلها را نمیتوان بارگیری کرد."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"افزودن به کنترلهای دستگاه"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"افزودن به موارد دلخواه"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> پیشنهاد میکند این کنترل به موارد دلخواهتان اضافه شود."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"افزودن"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"پیشنهاد <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"کنترلها بهروزرسانی شد"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"پین شامل حروف یا نماد است"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"تأیید <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3efc0d8..a3c1e5e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -28,7 +28,7 @@
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä"</string>
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> käytettävissä, noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä käytön perusteella"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> käytettävissä, noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä"</string>
- <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä. Virransäästö on käytössä."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä. Virransäästö on päällä."</string>
<string name="invalid_charger" msgid="4370074072117767416">"Lataaminen USB:llä ei onnistu. Käytä laitteesi mukana tullutta laturia."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Lataaminen USB:llä ei onnistu"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Käytä laitteesi mukana tullutta laturia"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Hylkää kuvakaappaus"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Kuvakaappauksen esikatselu"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Aloitetaanko tallennus?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Tallennuksen aikana Android-järjestelmä voi tallentaa mitä tahansa näytöllä näkyvää tai laitteen toistamaa arkaluontoista tietoa. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja äänisisältö."</string>
@@ -428,7 +429,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on poistettu käytöstä"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on käytössä"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Näytön tallentaminen"</string>
+ <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Tallennus"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Aloita"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Lopeta"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Laite"</string>
@@ -498,7 +499,7 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"Poistetaanko käyttäjä?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Kaikki käyttäjän tiedot ja sovellukset poistetaan."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Poista"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"Virransäästö on käytössä"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Virransäästö on päällä"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Poista virransäästö käytöstä"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> saa pääsyn kaikkiin näytölläsi näkyviin tietoihin ja tietoihin laitteesi toistamasta sisällöstä tallennuksen tai striimauksen aikana. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja toistettava audiosisältö."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Poista kaikki"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Muuta asetuksia"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Saapuvat"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Hiljaiset ilmoitukset"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Ääni-ilmoitukset"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Keskustelut"</string>
@@ -851,7 +853,7 @@
<string name="left_icon" msgid="5036278531966897006">"Vasen kuvake"</string>
<string name="right_icon" msgid="1103955040645237425">"Oikea kuvake"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Lisää osioita koskettamalla pitkään ja vetämällä"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Järjestele osioita koskettamalla pitkään ja vetämällä"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Järjestele koskettamalla pitkään ja vetämällä"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Poista vetämällä tähän."</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kiekkoa on vähimmäismäärä"</string>
<string name="qs_edit" msgid="5583565172803472437">"Muokkaa"</string>
@@ -964,8 +966,8 @@
<string name="qs_dnd_replace" msgid="7712119051407052689">"Korvaa"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Sovelluksia käynnissä taustalla"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Katso lisätietoja akun ja datan käytöstä napauttamalla"</string>
- <string name="mobile_data_disable_title" msgid="5366476131671617790">"Poistetaanko mobiilidata käytöstä?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> ei voi enää tarjota sinulle internetyhteyttä. Internetyhteys voidaan muodostaa vain Wi-Fi-verkossa."</string>
+ <string name="mobile_data_disable_title" msgid="5366476131671617790">"Laitetaanko mobiilidata pois päältä?"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> ei enää tarjoa pääsyä dataan eikä internetyhteyttä, joka on saatavilla vain Wi-Fin kautta."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operaattorisi"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Sovellus peittää käyttöoikeuspyynnön, joten Asetukset ei voi vahvistaa valintaasi."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Saako <xliff:g id="APP_0">%1$s</xliff:g> näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Ei nimeä"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Napauta, niin sovellus käynnistyy uudelleen ja siirtyy koko näytön tilaan."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Kuplien asetukset: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Ylivuoto"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Lisää takaisin pinoon"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Ylläpidä"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) ja <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> muuta"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kaikkien säätimien luetteloa ei voitu ladata."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Lisää laitteiden hallintaan"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Lisää suosikkeihin"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ehdotti tämän säätimen lisäämistä suosikkeihisi."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisää"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Ehdottaja: <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Säätimet päivitetty"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koodi sisältää kirjaimia tai symboleja"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Vahvista <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 25f886d3..b34a038 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Fermer la capture d\'écran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Commencer l\'enregistrement?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Durant l\'enregistrement, le système Android peut capturer de l\'information confidentielle qui s\'affiche sur votre écran ou qui joue sur votre appareil. Cela comprend les mots de passe, les renseignements sur le paiement, les photos, les messages et l\'audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notifications silencieuses"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notifications d\'alerte"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Touchez pour redémarrer cette application et passer en plein écran."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Paramètres pour les bulles de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu déroulant"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Replacer sur la pile"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gérer"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger la liste des commandes."</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_ok" msgid="7011816381344485651">"Ajouter aux favoris"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"L\'application <xliff:g id="APP">%s</xliff:g> a suggéré d\'ajouter cette commande à vos favoris."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le NIP contient des lettres ou des symboles"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Vérifier <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0c8bb93..1ec0411 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -36,7 +36,7 @@
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activer l\'économiseur de batterie ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"À propos de l\'économiseur de batterie"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activer"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activer l\'économiseur de batterie ?"</string>
+ <string name="battery_saver_start_action" msgid="4553256017945469937">"Activer l\'économiseur de batterie"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Paramètres"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotation automatique de l\'écran"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Fermer la capture d\'écran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Démarrer l\'enregistrement ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Pendant l\'enregistrement, le système Android peut capturer toute information sensible affichée à l\'écran ou lue sur votre appareil. Ceci inclut les mots de passe, les informations de paiement, les photos, les messages et les contenus audio."</string>
@@ -100,7 +101,7 @@
<string name="screenrecord_start" msgid="330991441575775004">"Démarrer"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Enregistrement de l\'écran"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Enregistrement de l\'écran et des contenus audio"</string>
- <string name="screenrecord_taps_label" msgid="1595690528298857649">"Afficher les points de l\'écran touchés"</string>
+ <string name="screenrecord_taps_label" msgid="1595690528298857649">"Afficher les points touchés sur l\'écran"</string>
<string name="screenrecord_stop_text" msgid="6549288689506057686">"Appuyez ici pour arrêter"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"Arrêter"</string>
<string name="screenrecord_pause_label" msgid="6004054907104549857">"Pause"</string>
@@ -155,7 +156,7 @@
<string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Mot de passe incorrect"</string>
<string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Trop de tentatives incorrectes.\nVeuillez réessayer dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
<string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Réessayez. Tentative <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> sur <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
- <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vos données seront supprimées"</string>
+ <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Risque de perte des données"</string>
<string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Si vous dessinez un schéma incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"Si vous saisissez un code incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"Si vous saisissez un mot de passe incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées."</string>
@@ -398,7 +399,7 @@
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"Partage de connexion"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Point d\'accès"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activation…"</string>
- <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Économ. données activé"</string>
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Écon. données activé"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
<item quantity="one">%d appareil</item>
<item quantity="other">%d appareils</item>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Notifications entrantes"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notifications silencieuses"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notifications d\'alerte"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -698,7 +700,7 @@
<string name="inline_block_button" msgid="479892866568378793">"Bloquer"</string>
<string name="inline_keep_button" msgid="299631874103662170">"Continuer d\'afficher les notifications"</string>
<string name="inline_minimize_button" msgid="1474436209299333445">"Réduire"</string>
- <string name="inline_silent_button_silent" msgid="525243786649275816">"Mode silencieux"</string>
+ <string name="inline_silent_button_silent" msgid="525243786649275816">"Silencieux"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"Notifications silencieuses"</string>
<string name="inline_silent_button_alert" msgid="5705343216858250354">"Alertes"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"Continuer de m\'avertir"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Appuyez pour redémarrer cette application et activer le mode plein écran."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Paramètres des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Dépassement"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Ajouter à nouveau l\'élément à la pile"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gérer"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de l\'application <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger toutes les commandes."</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_ok" msgid="7011816381344485651">"Ajouter aux favoris"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> a suggéré d\'ajouter cette commande aux favoris."</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>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le code contient des lettres ou des symboles"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Valider <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index de290e0..0095bcc 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -76,7 +76,7 @@
<string name="learn_more" msgid="4690632085667273811">"Máis información"</string>
<string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string>
- <string name="global_action_screenshot" msgid="2760267567509131654">"Crear captura"</string>
+ <string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora a captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa da captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravadora da pantalla"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Queres iniciar a gravación?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Durante a gravación, o sistema Android pode captar información confidencial visible na pantalla ou reproducila no dispositivo. Isto inclúe contrasinais, información de pago, fotos, mensaxes e audio."</string>
@@ -380,7 +381,7 @@
<string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"Wifi activada"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Non hai redes wifi dispoñibles"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activando…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Emisión da pantalla"</string>
+ <string name="quick_settings_cast_title" msgid="2279220930629235211">"Emitir pantalla"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Emitindo"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sen nome"</string>
<string name="quick_settings_cast_device_default_description" msgid="2580520859212250265">"Listo para emitir"</string>
@@ -435,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Pasar o dedo cara arriba para cambiar de aplicación"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra cara á dereita para cambiar de aplicacións rapidamente"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activar/desactivar Visión xeral"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargada"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargado"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completar a carga"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Non está cargando"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todas"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificacións silenciadas"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificación de alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -895,7 +897,7 @@
<string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Abrir configuración rápida."</string>
<string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Pechar a configuración rápida."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Alarma definida."</string>
- <string name="accessibility_quick_settings_user" msgid="505821942882668619">"Iniciaches sesión como <xliff:g id="ID_1">%s</xliff:g>"</string>
+ <string name="accessibility_quick_settings_user" msgid="505821942882668619">"Sesión iniciada como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Non hai conexión a Internet"</string>
<string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir detalles."</string>
<string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"Opcións non-dispoñibles polo seguinte motivo: <xliff:g id="REASON">%s</xliff:g>"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sen título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toca o botón para reiniciar esta aplicación e abrila en pantalla completa."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuración das burbullas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Mostrar menú adicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Engadir de novo á pilla"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Xestionar"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> e <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> máis"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Non se puido cargar a lista de todos os controis."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outra"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Engadir ao control de dispositivos"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Engadir a favoritos"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suxeriu que se engada este control aos teus favoritos."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Engadir"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Control suxerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Actualizáronse os controis"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contén letras ou símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index afbe13b..6d2dec8 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"સ્ક્રીનશૉટ છોડી દો"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકૉર્ડર"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"રેકૉર્ડિંગ શરૂ કરીએ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"રેકૉર્ડ કરતી વખતે, Android System તમારી સ્ક્રીન પર દેખાતી હોય અથવા તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી કોઈપણ સંવેદનશીલ માહિતીને કૅપ્ચર કરી શકે છે. આમાં પાસવર્ડ, ચુકવણીની માહિતી, ફોટા, સંદેશા અને ઑડિયોનો સમાવેશ થાય છે."</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"સૂચના કાઢી નાખી."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"બબલ છોડી દેવાયો."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ્સ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string>
@@ -414,7 +414,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> વાપર્યો"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> મર્યાદા"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
- <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"કાર્યાલયની પ્રોફાઇલ"</string>
+ <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"ઑફિસની પ્રોફાઇલ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"રાત્રિ પ્રકાશ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"સૂર્યાસ્ત વખતે"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"સૂર્યોદય સુધી"</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"મેનેજ કરો"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ઇતિહાસ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ઇનકમિંગ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"સાઇલન્ટ નોટિફિકેશન"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"નોટિફિકેશન બદલી રહ્યાં છીએ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string>
@@ -650,7 +651,7 @@
<string name="show_demo_mode" msgid="3677956462273059726">"ડેમો મોડ બતાવો"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"ઇથરનેટ"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"એલાર્મ"</string>
- <string name="status_bar_work" msgid="5238641949837091056">"કાર્યાલયની પ્રોફાઇલ"</string>
+ <string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string>
<string name="add_tile" msgid="6239678623873086686">"ટાઇલ ઉમેરો"</string>
<string name="broadcast_tile" msgid="5224010633596487481">"બ્રોડકાસ્ટ ટાઇલ"</string>
@@ -660,7 +661,7 @@
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> એ"</string>
<string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ઝડપી સેટિંગ્સ, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"હૉટસ્પૉટ"</string>
- <string name="accessibility_managed_profile" msgid="4703836746209377356">"કાર્યાલયની પ્રોફાઇલ"</string>
+ <string name="accessibility_managed_profile" msgid="4703836746209377356">"ઑફિસની પ્રોફાઇલ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"કેટલાક માટે મજા પરંતુ બધા માટે નહીં"</string>
<string name="tuner_warning" msgid="1861736288458481650">"સિસ્ટમ UI ટ્યૂનર તમને Android વપરાશકર્તા ઇન્ટરફેસને ટ્વીક અને કસ્ટમાઇઝ કરવાની વધારાની રીતો આપે છે. ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
@@ -802,7 +803,7 @@
<string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"ઍપ્લિકેશનો"</string>
<string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"સહાય"</string>
<string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"બ્રાઉઝર"</string>
- <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"સંપર્કો"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Contacts"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"ઇમેઇલ"</string>
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"સંગીત"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
<string name="restart_button_description" msgid="6916116576177456480">"આ ઍપ ફરીથી ચાલુ કરવા માટે ટૅપ કરીને પૂર્ણ સ્ક્રીન કરો."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> બબલ માટેનાં સેટિંગ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ઓવરફ્લો"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"સ્ટૅકમાં ફરી ઉમેરો"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"મેનેજ કરો"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> તરફથી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> અને વધુ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> તરફથી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"પાવર મેનૂમાંથી ઍક્સેસ કરવા માટેના નિયંત્રણોને પસંદ કરો"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"નિયંત્રણોને ફરીથી ગોઠવવા માટે તેમને હોલ્ડ કરીને ખેંચો"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"બધા નિયંત્રણો કાઢી નાખ્યા"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ફેરફારો સાચવ્યા નથી"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"બધા નિયંત્રણોની સૂચિ લોડ કરી શકાઈ નથી."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"અન્ય"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ડિવાઇસનાં નિયંત્રણોમાં ઉમેરો"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"મનપસંદમાં ઉમેરો"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> એ આ નિયંત્રણને તમારા મનપસંદમાં ઉમેરવાનું સૂચવ્યું છે."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ઉમેરો"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> દ્વારા સૂચન કરેલા"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"નિયંત્રણ અપડેટ કર્યા"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"પિનમાં અક્ષરો અથવા પ્રતીકોનો સમાવેશ થાય છે"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ને ચકાસો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index df76774..c7211f7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"स्क्रीनशॉट खारिज करें"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉट की झलक"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"रिकॉर्डिंग शुरू करना चाहते हैं?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"रिकॉर्ड करते समय, Android सिस्टम आपकी स्क्रीन पर दिखने वाली या चलाई जाने वाली संवेदनशील जानकारी को कैप्चर कर सकता है. इसमें पासवर्ड, पैसे चुकाने से जुड़ी जानकारी, फ़ोटो, मैसेज, और ऑडियो शामिल हैं."</string>
@@ -257,8 +258,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना खारिज की गई."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"बबल खारिज किया गया."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"त्वरित सेटिंग."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
@@ -356,7 +356,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"सुनने में मददगार डिवाइस"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"कान की मशीन"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ब्लूटूथ चालू हो रहा है…"</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"स्क्रीन की रोशनी"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अपने-आप घूमना"</string>
@@ -512,6 +512,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"सभी को हटाएं"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"प्रबंधित करें"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"हाल ही में मिली सूचनाएं"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"बिना आवाज़ या वाइब्रेशन वाली सूचनाएं"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"आवाज़ या वाइब्रेशन वाली सूचनाएं"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string>
@@ -587,7 +588,7 @@
<string name="accessibility_volume_settings" msgid="1458961116951564784">"साउंड सेटिंग"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"विस्तार करें"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"छोटा करें"</string>
- <string name="volume_odi_captions_tip" msgid="8825655463280990941">"ऑडियो-वीडियो पहचानकर अपने-आप कैप्शन बनना"</string>
+ <string name="volume_odi_captions_tip" msgid="8825655463280990941">"ऑडियो-वीडियो से अपने-आप कैप्शन बनना"</string>
<string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"कैप्शन सलाह बंद करें"</string>
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"कैप्शन ऊपर लगाएं"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"चालू करें"</string>
@@ -990,6 +991,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string>
<string name="restart_button_description" msgid="6916116576177456480">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन चालू करने के लिए टैप करें."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबल्स की सेटिंग"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ओवरफ़्लो"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"स्टैक में वापस जोड़ें"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"प्रबंधित करें"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> और <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> अन्य ऐप्लिकेशन से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1030,13 +1033,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"पावर मेन्यू से ऐक्सेस करने के लिए कंट्रोल चुनें"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"कंट्रोल का क्रम फिर से बदलने के लिए उन्हें दबाकर रखें और खींचें"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"सभी कंट्रोल हटा दिए गए"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"बदलाव सेव नहीं किए गए"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"सभी कंट्रोल की सूची लोड नहीं हो सकी."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"डिवाइस कंट्रोल में जोड़ें"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"पसंदीदा में जोड़ें"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> आपको इस कंट्रोल को अपनी पसंदीदा में जोड़ने का सुझाव देता है."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"जोड़ें"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> से मिला सुझाव"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"कंट्रोल अपडेट किए गए"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिन में अक्षर या चिह्न शामिल होते हैं"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> की पुष्टि करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 488de5d..34f9b7a 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Dopusti"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Otklanjanje pogrešaka putem USB-a nije dopušteno"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Korisnik koji je trenutačno prijavljen na ovaj uređaj ne može uključiti otklanjanje pogrešaka putem USB-a. Da biste upotrebljavali tu značajku, prijeđite na primarnog korisnika."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Želite li dopustiti bežično otklanjanje pogrešaka na ovoj mreži?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Dopuštate li bežično otklanjanje pogrešaka na ovoj mreži?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fija (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Uvijek dopusti na ovoj mreži"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Dopusti"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Odbacivanje snimke zaslona"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimke zaslona"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač zaslona"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Tekuća obavijest za sesiju snimanja zaslona"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Želite li započeti snimanje?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Za vrijeme snimanja sustav Android može snimiti osjetljive podatke koji su vidljivi na vašem zaslonu ili se reproduciraju na vašem uređaju. To uključuje zaporke, podatke o plaćanju, fotografije, poruke i zvuk."</string>
@@ -415,7 +416,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> iskorišteno"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Radni profil"</string>
+ <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Poslovni profil"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Noćno svjetlo"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Uključuje se u suton"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do izlaska sunca"</string>
@@ -512,8 +513,9 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Povijest"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Bešumne obavijesti"</string>
- <string name="notification_section_header_alerting" msgid="3168140660646863240">"Upozoravajuće obavijesti"</string>
+ <string name="notification_section_header_alerting" msgid="3168140660646863240">"Zvučne obavijesti"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Izbriši sve bešumne obavijesti"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Značajka Ne uznemiravaj pauzirala je Obavijesti"</string>
@@ -652,7 +654,7 @@
<string name="show_demo_mode" msgid="3677956462273059726">"Prikaži demo način"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
- <string name="status_bar_work" msgid="5238641949837091056">"Radni profil"</string>
+ <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodavanje pločice"</string>
<string name="broadcast_tile" msgid="5224010633596487481">"Emitiranje pločice"</string>
@@ -662,7 +664,7 @@
<string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Brze postavke, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Žarišna točka"</string>
- <string name="accessibility_managed_profile" msgid="4703836746209377356">"Radni profil"</string>
+ <string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Ugađanje korisničkog sučelja sustava pruža vam dodatne načine za prilagodbu korisničkog sučelja Androida. Te se eksperimentalne značajke mogu promijeniti, prekinuti ili nestati u budućim izdanjima. Nastavite uz oprez."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Te se eksperimentalne značajke mogu promijeniti, prekinuti ili nestati u budućim izdanjima. Nastavite uz oprez."</string>
@@ -992,6 +994,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dodirnite da biste ponovo pokrenuli tu aplikaciju i prikazali je na cijelom zaslonu."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Postavke za oblačiće za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Dodatno"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodajte natrag u nizove"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljanje"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1037,8 +1041,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Popis svih kontrola nije se učitao."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodavanje kontrolama uređaja"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodaj u favorite"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacija <xliff:g id="APP">%s</xliff:g> predlaže dodavanje ove kontrole u vaše favorite."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Preporuka s kanala <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index d44f837..45462d4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Képernyőkép elvetése"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Képernyőkép előnézete"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Képernyőrögzítő"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Elindítja a felvételt?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"A felvétel készítése során az Android rendszer rögzítheti az eszközön lejátszott, illetve a képernyőjén megjelenő bizalmas információkat. Ide tartoznak például a jelszavak, a fizetési információk, a fotók, az üzenetek és az audiotartalmak is."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Az összes törlése"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Kezelés"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Előzmények"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Bejövő"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Néma értesítések"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Figyelemfelkeltő értesítések"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Beszélgetések"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"A háttérben még futnak alkalmazások"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Koppintson az akkumulátor- és adathasználat részleteinek megtekintéséhez"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Kikapcsolja a mobiladatokat?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nem lesz adat-, illetve internet-hozzáférése a(z) <xliff:g id="CARRIER">%s</xliff:g> szolgáltatón keresztül. Az internethez csak Wi-Fi-n keresztül csatlakozhat."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nem lesz adat-, illetve internet-hozzáférése a <xliff:g id="CARRIER">%s</xliff:g> szolgáltatón keresztül. Az internethez csak Wi-Fi-n keresztül csatlakozhat."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"saját mobilszolgáltató"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Mivel az egyik alkalmazás eltakarja az engedélykérést, a Beállítások alkalmazás nem tudja ellenőrizni az Ön válaszát."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Engedélyezi a(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazásnak, hogy részleteket mutasson a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból?"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Nincs cím"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Koppintson az alkalmazás újraindításához és a teljes képernyős mód elindításához."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g>-buborékok beállításai"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"További elemeket tartalmazó menü"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Visszaküldés a verembe"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Kezelés"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> a(z) <xliff:g id="APP_NAME">%2$s</xliff:g> alkalmazásból és <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> további"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nem sikerült betölteni az összes vezérlő listáját."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Hozzáadás az eszközvezérlőkhöz"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Hozzáadás a kedvencekhez"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"A(z) <xliff:g id="APP">%s</xliff:g> azt javasolta, hogy adja hozzá ezt a vezérlőt a kedvenceihez."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Hozzáadás"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> javasolta"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Vezérlők frissítve"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"A PIN-kód betűket vagy szimbólumokat tartalmaz"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ellenőrzése"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 1ce80ff..33cf2a3 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Փակել սքրինշոթը"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Սքրինշոթի նախադիտում"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Սկսե՞լ տեսագրումը"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Տեսագրման ընթացքում Android-ի համակարգը կարող է գրանցել անձնական տեղեկություններ, որոնք տեսանելի են էկրանին կամ նվագարկվում են ձեր սարքում։ Սա ներառում է այնպիսի տեղեկություններ, ինչպիսիք են, օրինակ, գաղտնաբառերը, վճարային տվյալները, լուսանկարները, հաղորդագրությունները և նվագարկվող աուդիո ֆայլերը։"</string>
@@ -193,8 +194,8 @@
<string name="accessibility_data_three_bars" msgid="3036562180893930325">"Տվյալների երեք գիծ:"</string>
<string name="accessibility_data_signal_full" msgid="283507058258113551">"Տվյալների ազդանշանը լրիվ է:"</string>
<string name="accessibility_wifi_name" msgid="4863440268606851734">"Միացված է <xliff:g id="WIFI">%s</xliff:g>-ին:"</string>
- <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Կապակցված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
- <string name="accessibility_cast_name" msgid="7344437925388773685">"Կապակցված է <xliff:g id="CAST">%s</xliff:g>-ին:"</string>
+ <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
+ <string name="accessibility_cast_name" msgid="7344437925388773685">"Միացված է <xliff:g id="CAST">%s</xliff:g>-ին:"</string>
<string name="accessibility_no_wimax" msgid="2014864207473859228">"WiMAX չկա:"</string>
<string name="accessibility_wimax_one_bar" msgid="2996915709342221412">"WiMAX-ի մեկ գիծ:"</string>
<string name="accessibility_wimax_two_bars" msgid="7335485192390018939">"WiMAX-ի երկու գիծ:"</string>
@@ -392,7 +393,7 @@
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Գունաշտկման ռեժիմ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Հավելյալ կարգավորումներ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Պատրաստ է"</string>
- <string name="quick_settings_connected" msgid="3873605509184830379">"Կապակցված է"</string>
+ <string name="quick_settings_connected" msgid="3873605509184830379">"Միացված է"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Միացված է, մարտկոցի լիցք՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"Միանում է..."</string>
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"Մոդեմի ռեժիմ"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Մաքրել բոլորը"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Կառավարել"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Պատմություն"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Մուտքային"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Անձայն ծանուցումներ"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Նախազգուշացնող ծանուցումներ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Խոսակցություններ"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Ֆոնային ռեժիմում աշխատող հավելվածներ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Հպեք՝ մարտկոցի և թրաֆիկի մանրամասները տեսնելու համար"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Անջատե՞լ բջջային ինտերնետը"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> օպերատորի բջջային ինտերնետը հասանելի չի լինի: Համացանցից կարող եք օգտվել միայն Wi-Fi-ի միջոցով:"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> օպերատորի բջջային ինտերնետը հասանելի չի լինի: Համացանցից կկարողանաք օգտվել միայն Wi-Fi-ի միջոցով:"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Ձեր"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Քանի որ ներածումն արգելափակված է ինչ-որ հավելվածի կողմից, Կարգավորումները չեն կարող հաստատել ձեր պատասխանը:"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Թույլատրե՞լ <xliff:g id="APP_0">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Հպեք՝ հավելվածը վերագործարկելու և լիաէկրան ռեժիմին անցնելու համար։"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ի ամպիկների կարգավորումներ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Լրացուցիչ ընտրացանկ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Նորից ավելացնել զտիչներում"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Կառավարել"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g>-ից"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>` <xliff:g id="APP_NAME">%2$s</xliff:g>-ից ու ևս <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ամպիկ"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Չհաջողվեց բեռնել բոլոր կառավարների ցանկը։"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Ավելացրեք սարքերի կառավարման տարրերում"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Ավելացնել ընտրանիում"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> հավելվածն առաջարկում է ավելացնել այս կառավարը ձեր ընտրանիում։"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Ավելացնել"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Առաջարկվել է <xliff:g id="APP">%s</xliff:g> հավելվածի կողմից"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Կառավարման տարրերը թարմացվեցին"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN կոդը տառեր և նշաններ է պարունակում"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Ստուգել <xliff:g id="DEVICE">%s</xliff:g> սարքը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 8f506952..35aabc7 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Menutup screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pratinjau screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Perekam Layar"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Mulai Merekam?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Saat merekam, Sistem Android dapat ikut merekam informasi sensitif yang terlihat di layar atau diputar di perangkat Anda. Informasi ini mencakup sandi, info pembayaran, foto, pesan, dan audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hapus semua"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Kelola"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Histori"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Masuk"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notifikasi senyap"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notifikasi aktif"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Percakapan"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Tanpa judul"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Ketuk untuk memulai ulang aplikasi ini dan membuka layar penuh."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Setelan untuk balon <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Tambahan"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Tambahkan kembali ke stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Kelola"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> lainnya"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Daftar semua kontrol tidak dapat dimuat."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan ke kontrol perangkat"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Tambahkan ke favorit"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> menyarankan kontrol ini ditambahkan ke favorit."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambahkan"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Disarankan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrol diperbarui"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN berisi huruf atau simbol"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifikasi <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index c3e33fc..52d63b0 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Loka skjámynd"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forskoðun skjámyndar"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Hefja upptöku?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Á meðan tekið er upp getur Android kerfið fangað viðkvæmar upplýsingar sem sjást á skjánum eða spilast í tækinu. Þar á meðal eru upplýsingar á borð við aðgangsorð, greiðsluupplýsingar, myndir, skilaboð og hljóð."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Stjórna"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Ferill"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Mótteknar"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Þöglar tilkynningar"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Viðvörunartilkynningar"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Samtöl"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Enginn titill"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Ýttu til að endurræsa forritið og sýna það á öllum skjánum."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Stillingar fyrir blöðrur frá <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Yfirflæði"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Bæta aftur í stafla"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Stjórna"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ frá <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> í viðbót"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ekki tókst að hlaða lista yfir allar stýringar."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Bæta við tækjastjórnun"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Bæta við uppáhald"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> stakk upp á að bæta þessari stýringu við uppáhald."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Bæta við"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Tillaga frá <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Stýringar uppfærðar"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN inniheldur bókstafi eða tákn"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Staðfesta <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index db33a9a..1a71d91 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Anteprima screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Avviare la registrazione?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Durante la registrazione, il sistema Android può acquisire dati sensibili visibili sullo schermo o riprodotti sul tuo dispositivo, tra cui password, dati di pagamento, foto, messaggi e audio."</string>
@@ -297,8 +298,8 @@
<string name="accessibility_quick_settings_flashlight_on" msgid="3785616827729850766">"Torcia accesa."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3782375441381402599">"Torcia disattivata."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="4747870681508334200">"Torcia attivata."</string>
- <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"Inversione colori disattivata."</string>
- <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"Inversione colori attivata."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"Inversione dei colori disattivata."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"Inversione dei colori attivata."</string>
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Hotspot mobile disattivato."</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Hotspot mobile attivato."</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Trasmissione dello schermo interrotta."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Cancella tutto"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gestisci"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Cronologia"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"In arrivo"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notifiche silenziose"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notifiche di avviso"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tocca per riavviare l\'app e passare a schermo intero."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Impostazioni per bolle <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Altre"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Aggiungi di nuovo all\'elenco"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gestisci"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g> e altre <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossibile caricare l\'elenco di tutti i controlli."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Aggiungi al controllo dei dispositivi"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Aggiungi ai preferiti"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ha suggerito di aggiungere questo controllo ai preferiti."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Aggiungi"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Suggerito da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlli aggiornati"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Il PIN contiene lettere o simboli"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f814e6b..121f9bb 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"סגירת צילום מסך"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"להתחיל את ההקלטה?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"בזמן ההקלטה, מערכת Android יכולה לתעד מידע רגיש שגלוי במסך או מופעל במכשיר שלך. מידע זה כולל סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו."</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכל"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"היסטוריה"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"התקבלו"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"התראות שקטות"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"התראות עם צלילים או רטט"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
<string name="restart_button_description" msgid="6916116576177456480">"צריך להקיש כדי להפעיל מחדש את האפליקציה הזו ולעבור למסך מלא."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"הגדרות בשביל בועות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"גלישה"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"הוספה בחזרה לערימה"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ניהול"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מהאפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מ-<xliff:g id="APP_NAME">%2$s</xliff:g> ועוד <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"לא ניתן היה לטעון את הרשימה של כל הפקדים."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"הוספה לפקדי המכשירים"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"הוספה למועדפים"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"בקרה זו הוצעה על ידי <xliff:g id="APP">%s</xliff:g> להוספה למועדפים."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"הוספה"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"הוצע על-ידי <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"הפקדים עודכנו"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"קוד האימות מכיל אותיות או סמלים"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"אימות <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4b5394f..42ecb64 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"スクリーンショットを閉じます"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"スクリーンショットのプレビュー"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"スクリーン レコーダー"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"画面の録画を処理しています"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"録画を開始しますか?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"録画中に機密情報が画面に表示されたりデバイスで再生されたりした場合、Android システムでキャプチャされることがあります。これには、パスワード、お支払い情報、写真、メッセージ、音声などが含まれます。"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"すべて消去"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"履歴"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"新着"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"サイレント通知"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"バイブレーションまたは音を伴う通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"会話"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"バックグラウンドで実行中のアプリ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"タップして電池やデータの使用量を確認"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"モバイルデータを OFF にしますか?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> でデータやインターネットにアクセスできなくなります。インターネットには Wi-Fi からのみ接続できます。"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g>でデータやインターネットにアクセスできなくなります。インターネットには Wi-Fi からのみ接続できます。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"携帯通信会社"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"アプリが許可リクエストを隠しているため、設定側でユーザーの応答を確認できません。"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示を「<xliff:g id="APP_0">%1$s</xliff:g>」に許可しますか?"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string>
<string name="restart_button_description" msgid="6916116576177456480">"タップしてこのアプリを再起動すると、全画面表示になります。"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> のバブルの設定"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"オーバーフロー"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"スタックに戻す"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)、他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 件"</string>
@@ -1024,15 +1028,15 @@
<item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> 件のコントロールを追加しました。</item>
</plurals>
<string name="controls_favorite_default_title" msgid="967742178688938137">"コントロール"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"電源メニューからアクセスするコントロールを選択する"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"電源ボタン メニューからアクセスするコントロールを選択する"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"コントロールを並べ替えるには長押ししてドラッグします"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"すべてのコントロールを削除しました"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"変更が保存されていません"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"全コントロールの一覧を読み込めませんでした。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"デバイス コントロールに追加"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"お気に入りに追加"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>が、お気に入りに追加のためにこのコントロールを提案しました。"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"追加"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> によるおすすめ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"コントロールを更新しました"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN に英字や記号を含める"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>の確認"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 242ee8d..36580b7 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ეკრანის ანაბეჭდის დახურვა"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ეკრანის ანაბეჭდის გადახედვა"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის ჩამწერი"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ეკრანის ჩანაწერი მუშავდება"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"უწყვეტი შეტყობინება ეკრანის ჩაწერის სესიისთვის"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"დაიწყოს ჩაწერა?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ჩაწერის განმავლობაში Android სისტემას შეუძლია აღბეჭდოს ნებისმიერი სენსიტიური ინფორმაცია, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება. აღნიშნული მოიცავს პაროლებს, გადახდის დეტალებს, ფოტოებს, შეტყობინებებსა და აუდიოს."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ყველას გასუფთავება"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"მართვა"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ისტორია"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"შემომავალი"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ჩუმი შეტყობინებები"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"გამაფრთხილებელი შეტყობინებები"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"უსათაურო"</string>
<string name="restart_button_description" msgid="6916116576177456480">"შეეხეთ ამ აპის გადასატვირთად და გადადით სრულ ეკრანზე."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"პარამეტრები <xliff:g id="APP_NAME">%1$s</xliff:g> ბუშტებისთვის"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"გადავსება"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ისევ დამატება დასტაზე"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"მართვა"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g>-ისგან"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g>-დან და კიდევ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"მართვის ყველა საშუალების სია ვერ ჩაიტვირთა."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"მოწყობილ. მართვის საშუალებებში დამატება"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"რჩეულებში დამატება"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> გთავაზობთ, მართვის ეს საშუალება თქვენს რჩეულებში დაამატოთ."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"დამატება"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"შემოთავაზებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"მართვის საშუალებები განახლდა"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-კოდი შეიცავს ასოებს ან სიმბოლოებს"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"დაადასტურეთ <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 598b281..53ead8e 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Скриншотты жабу"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотты алдын ала қарау"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Жазу басталсын ба?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Жазу кезінде Android жүйесі экранда көрсетілетін немесе құрылғыда ойнатылатын құпия ақпаратты пайдалана алады. Ол ақпаратқа құпия сөздер, төлеу ақпараты, фотосуреттер, хабарлар және аудио жатады."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Барлығын тазалау"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Басқару"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Тарих"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Кіріс"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Дыбыссыз хабарландырулар"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Ескертуші хабарландлырулар"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string>
@@ -584,7 +586,7 @@
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Дыбыс параметрлері"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"Жаю"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"Жию"</string>
- <string name="volume_odi_captions_tip" msgid="8825655463280990941">"Автоматты субтитр медиасы"</string>
+ <string name="volume_odi_captions_tip" msgid="8825655463280990941">"Автоматты субтитр қосу"</string>
<string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"Субтитрлер кеңесі"</string>
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Субтитр қою"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"қосу"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> қалқыма хабарларының параметрлері"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Қосымша мәзір"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Стекке қайта енгізу"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Басқару"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> жіберген хабарландыру: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасы жіберген <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> және тағы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Барлық басқару элементі тізімі жүктелмеді."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғы басқару виджеттеріне қосу"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Таңдаулыларға қосу"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> қолданбасы бұл басқару элементін таңдаулыларға қосып қоюды ұсынды."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Енгізу"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ұсынған"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Басқару элементтері жаңартылды"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN коды әріптерден не таңбалардан құралады."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> растау"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index fc13931..a33b9f5 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ច្រានចោលរូបថតអេក្រង់"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ការមើលរូបថតអេក្រង់សាកល្បង"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថតអេក្រង់"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុងដំណើរការការថតអេក្រង់"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹងដែលកំពុងដំណើរការសម្រាប់រយៈពេលប្រើការថតសកម្មភាពអេក្រង់"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ចាប់ផ្តើមថតឬ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"នៅពេលកំពុងថត ប្រព័ន្ធ Android អាចថតព័ត៌មានរសើបដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលបានចាក់នៅលើឧបករណ៍របស់អ្នក។ ព័ត៌មាននេះរួមមានពាក្យសម្ងាត់ ព័ត៌មានអំពីការបង់ប្រាក់ រូបថត សារ និងសំឡេង។"</string>
@@ -367,7 +368,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ទីតាំងបានបិទ"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ឧបករណ៍មេឌៀ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
- <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"សម្រាប់តែការហៅពេលអាសន្ន"</string>
+ <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់តែប៉ុណ្ណោះ"</string>
<string name="quick_settings_settings_label" msgid="2214639529565474534">"ការកំណត់"</string>
<string name="quick_settings_time_label" msgid="3352680970557509303">"ពេលវេលា"</string>
<string name="quick_settings_user_label" msgid="1253515509432672496">"ខ្ញុំ"</string>
@@ -380,7 +381,7 @@
<string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"Wi-Fi បានបើក"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"គ្មានបណ្តាញ Wi-Fi ទេ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"កំពុងបើក..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ការថតវីដេអូនៅលើអេក្រង់"</string>
+ <string name="quick_settings_cast_title" msgid="2279220930629235211">"ការបញ្ចាំងអេក្រង់"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ការចាត់ថ្នាក់"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ឧបករណ៍ដែលមិនមានឈ្មោះ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2580520859212250265">"ត្រៀមរួចរាល់ដើម្បីចាត់ថ្នាក់"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាតទាំងអស់"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"គ្រប់គ្រង"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ប្រវត្តិ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"មកដល់"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ការជូនដំណឹងស្ងាត់"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"ការជូនដំណឹងញ័រ ឬរោទ៍"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ការសន្ទនា"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"គ្មានចំណងជើង"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ចុចដើម្បីចាប់ផ្ដើមកម្មវិធីនេះឡើងវិញ រួចចូលប្រើពេញអេក្រង់។"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"ការកំណត់សម្រាប់ពពុះ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ម៉ឺនុយបន្ថែម"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"បញ្ចូលទៅក្នុងគំនរវិញ"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"គ្រប់គ្រង"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g> និង <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ទៀត"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"មិនអាចផ្ទុកបញ្ជីនៃការគ្រប់គ្រងទាំងអស់បានទេ។"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"បញ្ចូលទៅក្នុងផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"បញ្ចូលទៅក្នុងសំណព្វ"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> បានណែនាំឱ្យបញ្ចូលការគ្រប់គ្រងនេះទៅក្នុងសំណព្វរបស់អ្នក។"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"បញ្ចូល"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"បានណែនាំដោយ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"បានធ្វើបច្ចុប្បន្នភាពការគ្រប់គ្រង"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"កូដ PIN មានអក្សរ ឬនិមិត្តសញ្ញា"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"ផ្ទៀងផ្ទាត់ <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 4dd6814..cca8c6b7 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -33,7 +33,7 @@
<string name="invalid_charger_title" msgid="938685362320735167">"USB ಮೂಲಕ ಚಾರ್ಜ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ನಿಮ್ಮ ಸಾಧನದೊಂದಿಗೆ ನೀಡಲಾಗಿರುವ ಚಾರ್ಜರ್ ಬಳಸಿ"</string>
<string name="battery_low_why" msgid="2056750982959359863">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಕುರಿತು"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ಆನ್ ಮಾಡಿ"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಮಾಡಿ"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ಸ್ಕ್ರೀನ್ಶಾಟ್ನ ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೆಶನ್ಗಾಗಿ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಅಧಿಸೂಚನೆ"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸಬೇಕೆ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ರೆಕಾರ್ಡಿಂಗ್ ಸಮಯದಲ್ಲಿ, ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾದ ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು Android ಸಿಸ್ಟಂ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಬಹುದು. ಇದು ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ಮಾಹಿತಿ, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಆಡಿಯೋವನ್ನು ಒಳಗೊಂಡಿದೆ."</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್ ಪರದೆ."</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ಒಳಬರುವ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"ಎಚ್ಚರಿಸುವ ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string>
@@ -961,7 +962,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"(<xliff:g id="ID_1">%s</xliff:g>) ಅಪ್ಲಿಕೇಶನ್ ಮೂಲಕ ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ಸ್ವಯಂಚಾಲಿತ ನಿಯಮ ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್ ಮೂಲಕ ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> ತನಕ"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"ಇರಿಸಿ"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"ಬದಲಿಸಿ"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿವೆ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ಬ್ಯಾಟರಿ,ಡೇಟಾ ಬಳಕೆಯ ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -982,12 +983,14 @@
<string name="auto_saver_enabled_text" msgid="7889491183116752719">"ಬ್ಯಾಟರಿ <xliff:g id="PERCENTAGE">%d</xliff:g>%% ಗಿಂತ ಕಡಿಮೆ ಆದಾಗ ಬ್ಯಾಟರಿ ಸೇವರ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಆಗುತ್ತದೆ."</string>
<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="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</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>
<string name="restart_button_description" msgid="6916116576177456480">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಬಬಲ್ಸ್ಗಾಗಿ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ಓವರ್ಫ್ಲೋ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ಸ್ಟ್ಯಾಕ್ಗೆ ಪುನಃ ಸೇರಿಸಿ"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ನಿರ್ವಹಿಸಿ"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಆ್ಯಪ್ನ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಮತ್ತು <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ಹೆಚ್ಚಿನವುಗಳ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ಪವರ್ ಮೆನುವಿನಿಂದ ಪ್ರವೇಶಿಸಲು ನಿಯಂತ್ರಣಗಳನ್ನು ಆರಿಸಿ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ನಿಯಂತ್ರಣಗಳನ್ನು ಮರುಹೊಂದಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಮತ್ತು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗಿಲ್ಲ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳ ಪಟ್ಟಿಯನ್ನು ಲೋಡ್ ಮಾಡಲು ಆಗಲಿಲ್ಲ."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ಇತರ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳಿಗೆ ಸೇರಿಸಿ"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ಮೆಚ್ಚಿನವುಗಳಿಗೆ ಸೇರಿಸಿ"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"ಈ ನಿಯಂತ್ರಣವನ್ನು ನಿಮ್ಮ ಮೆಚ್ಚಿನವುಗಳಿಗೆ ಸೇರಿಸಲು <xliff:g id="APP">%s</xliff:g> ಸೂಚಿಸಿದೆ."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ಸೇರಿಸಿ"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಸೂಚಿಸಿದೆ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ನಿಯಂತ್ರಣಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ಪಿನ್ ಅಕ್ಷರಗಳು ಅಥವಾ ಸಂಕೇತಗಳನ್ನು ಒಳಗೊಂಡಿದೆ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index a56bf4a..60ecdb7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"스크린샷 닫기"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"스크린샷 미리보기"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"화면 녹화"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"녹화를 시작하시겠습니까?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Android 시스템이 녹화 중에 화면에 표시되거나 기기에서 재생되는 민감한 정보를 캡처할 수 있습니다. 여기에는 비밀번호, 결제 정보, 사진, 메시지 및 오디오가 포함됩니다."</string>
@@ -398,7 +399,7 @@
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"테더링"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"핫스팟"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"켜는 중..."</string>
- <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"데이터 절약 모드 사용 중"</string>
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"데이터 절약 모드"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
<item quantity="other">기기 %d대</item>
<item quantity="one">기기 %d대</item>
@@ -488,7 +489,7 @@
<string name="user_logout_notification_title" msgid="3644848998053832589">"사용자 로그아웃"</string>
<string name="user_logout_notification_text" msgid="7441286737342997991">"현재 사용자 로그아웃"</string>
<string name="user_logout_notification_action" msgid="7974458760719361881">"사용자 로그아웃"</string>
- <string name="user_add_user_title" msgid="4172327541504825032">"새 사용자를 추가할까요?"</string>
+ <string name="user_add_user_title" msgid="4172327541504825032">"신규 사용자를 추가할까요?"</string>
<string name="user_add_user_message_short" msgid="2599370307878014791">"추가된 새로운 사용자는 자신의 공간을 설정해야 합니다.\n\n모든 사용자는 다른 사용자들을 위하여 앱을 업데이트할 수 있습니다."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"사용자 제한 도달"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
@@ -509,11 +510,12 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"모두 지우기"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"관리"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"기록"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"최근 알림"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"무음 알림"</string>
- <string name="notification_section_header_alerting" msgid="3168140660646863240">"주의를 끄는 알림"</string>
+ <string name="notification_section_header_alerting" msgid="3168140660646863240">"소리 알림"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"대화"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"무음 알림 모두 삭제"</string>
- <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"방해 금지 모드로 일시중지된 알림"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"방해 금지 모드로 알림이 일시중지됨"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"시작하기"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"알림 없음"</string>
<string name="profile_owned_footer" msgid="2756770645766113964">"프로필이 모니터링될 수 있음"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"백그라운드에서 실행 중인 앱"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"탭하여 배터리 및 데이터 사용량 확인"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"모바일 데이터를 사용 중지하시겠습니까?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g>을(를) 통해 데이터 또는 인터넷에 액세스할 수 없습니다. 인터넷은 Wi-Fi를 통해서만 사용할 수 있습니다."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g>을(를) 통해 데이터 또는 인터넷에 액세스할 수 없게 됩니다. 인터넷은 Wi-Fi를 통해서만 사용할 수 있습니다."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"이동통신사"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"앱이 권한 요청을 가리고 있기 때문에 설정에서 내 응답을 확인할 수 없습니다."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하도록 허용하시겠습니까?"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
<string name="restart_button_description" msgid="6916116576177456480">"탭하여 이 앱을 다시 시작하고 전체 화면으로 이동합니다."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> 대화창 설정"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"더보기"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"스택에 다시 추가"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"관리"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>개의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"전체 컨트롤 목록을 로드할 수 없습니다."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"기기 제어에 추가"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"즐겨찾기에 추가"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>에서 이 제어 기능을 즐겨찾기에 추가할 것을 제안합니다."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"추가"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>에서 제안"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"컨트롤 업데이트됨"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN에 문자나 기호가 포함됨"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> 확인"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index fda3a05..6893e8f 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -62,8 +62,8 @@
<string name="usb_debugging_always" msgid="4003121804294739548">"Бул компүтерден дайыма уруксат берилсин"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Уруксат берүү"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB мүчүлүштүктөрүн оңдоого уруксат жок"</string>
- <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Учурда бул аккаунтта USB аркылуу мүчүлүштүктөрдү оңдоо функциясын иштетүүгө болбойт. Негизги колдонуучунун аккаунтуна кириңиз."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Бул тармакта мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат берилсинби?"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Учурда бул аккаунтта USB аркылуу мүчүлүштүктөрдү аныктоо функциясын иштетүүгө болбойт. Негизги колдонуучунун аккаунтуна кириңиз."</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Ушул тармакта мүчүлүштүктөрдү Wi-Fi аркылуу аныктоого уруксат бересизби?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Тармактын аталышы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi дареги (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Бул тармакта ар дайым уруксат берилсин"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Уруксат берүү"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Скриншотту четке кагуу"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотту алдын ала көрүү"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Жаздырып баштайсызбы?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Жаздыруу учурунда Android тутуму экраныңызда көрүнүп турган жана түзмөктө ойноп жаткан бардык купуя маалыматты жаздырып алат. Буга сырсөздөр, төлөм маалыматы, сүрөттөр, билдирүүлөр жана аудио файлдар кирет."</string>
@@ -153,21 +154,21 @@
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"PIN код туура эмес"</string>
<string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Графикалык ачкыч туура эмес"</string>
<string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Сырсөз туура эмес"</string>
- <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Өтө көп жолу туура эмес аракет кылынды.\n<xliff:g id="NUMBER">%d</xliff:g> секунддан кийин кайра кайталаңыз."</string>
+ <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Өтө көп жолу жаңылдыңыз.\n<xliff:g id="NUMBER">%d</xliff:g> секунддан кийин кайра кайталаңыз."</string>
<string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Кайра кайталаңыз. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> аракеттен <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> аракет калды."</string>
- <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Дайын-даректериңиз өчүрүлөт"</string>
+ <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Акыркы аракет калды"</string>
<string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Эгер графикалык ачкычты кийинки жолу туура эмес киргизсеңиз, бул түзмөктүн маалыматы өчүрүлөт."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"Эгер PIN кодду кийинки жолу туура эмес киргизсеңиз, бул түзмөктүн маалыматы өчүрүлөт."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"Эгер сырсөздү кийинки жолу туура эмес киргизсеңиз, бул түзмөктүн маалыматы өчүрүлөт."</string>
<string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Эгер графикалык кийинки жолу туура эмес киргизсеңиз, бул колдонуучу өчүрүлөт."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Эгер PIN кодду кийинки жолу туура эмес киргизсеңиз, бул колдонуучу өчүрүлөт."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Эгер сырсөздү кийинки жолу туура эмес киргизсеңиз, бул колдонуучу өчүрүлөт."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Эгер графикалык ачкычты кийинки жолу туура эмес киргизсеңиз, жумуш профилиңиз жана анын маалыматы өчүрүлөт."</string>
- <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Эгер PIN кодду кийинки жолу туура эмес киргизсеңиз, жумуш профилиңиз жана анын маалыматы өчүрүлөт."</string>
- <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Эгер сырсөздү кийинки жолу туура эмес киргизсеңиз, жумуш профилиңиз жана анын маалыматы өчүрүлөт."</string>
- <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Өтө көп жолу туура эмес аракет кылынды. Бул түзмөктүн маалыматы өчүрүлөт."</string>
- <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Өтө көп жолу туура эмес аракет кылынды. Бул колдонуучу өчүрүлөт."</string>
- <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Өтө көп жолу туура эмес аракет кылынды. Бул жумуш профили жана андагы маалымат өчүрүлөт."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Эгер графикалык ачкычты дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Эгер PIN кодду дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
+ <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Эгер сырсөздү дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
+ <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Өтө көп жолу жаңылдыңыз. Бул түзмөктөгү дайын-даректер өчүрүлөт."</string>
+ <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Өтө көп жолу жаңылдыңыз. Бул колдонуучу өчүрүлөт."</string>
+ <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Өтө көп жолу жаңылдыңыз. Бул жумуш профили жана андагы маалымат өчүрүлөт."</string>
<string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Жабуу"</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Манжа изинин сенсорун басыңыз"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Манжа изинин сүрөтчөсү"</string>
@@ -374,7 +375,7 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Колдонуучу"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңы колдонуучу"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
- <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Туташкан жок"</string>
+ <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Байланышкан жок"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желе жок"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өчүк"</string>
<string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"Wi-Fi күйүк"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Башкаруу"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Таржымал"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Кирүүчү"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Үнсүз билдирмелер"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Эскертүүлөр"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Жазышуулар"</string>
@@ -707,7 +709,7 @@
<string name="notification_silence_title" msgid="8608090968400832335">"Үнсүз"</string>
<string name="notification_alert_title" msgid="7629202599338071971">"Шашылыш билдирүү"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Көбүк"</string>
- <string name="notification_channel_summary_low" msgid="7300447764759926720">"Үн же дирилдөөсүз ой топтоого жардам берет."</string>
+ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Билдирмелер келгенде, үн чыкпайт же дирилдебейт."</string>
<string name="notification_channel_summary_default" msgid="3539949463907902037">"Билдирүүдөн үн чыгат же дирилдейт."</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="6298026344552480458">"Билдирүүдөн үн чыгат же дирилдейт. <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жазышуулар демейки жөндөө боюнча калкып чыкма билдирмелер болуп көрүнөт."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Калкыма ыкчам баскыч менен көңүлүңүздү бул мазмунга буруп турат."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Бул колдонмону өчүрүп күйгүзүп, толук экранга өтүү үчүн, таптап коюңуз."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Кошумча меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Кайра топтомго кошуу"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Башкаруу"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> жана дагы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> колдонмодон <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бардык көзөмөлдөрдүн тизмеси жүктөлгөн жок."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Түзмөктү башкаруу элементтерине кошуу"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Сүйүктүүлөргө кошуу"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> бул көзөмөлдү сүйүктүүлөргө кошууну сунуштады."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Кошуу"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> сунуштайт"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Башкаруу элементтери жаңырды"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгаларды же символдорду камтыйт"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> түзмөгүн ырастаңыз"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 5a8c5dc..d118d89 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -40,4 +40,6 @@
<!-- Padding between status bar and bubbles when displayed in expanded state, smaller
value in landscape since we have limited vertical space-->
<dimen name="bubble_padding_top">4dp</dimen>
+
+ <dimen name="controls_activity_view_top_offset">25dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1ff99d5..2514b3e 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4811759950673118541">"ສ່ວນຕິດຕໍ່ຜູ່ໃຊ້ຂອງລະບົບ"</string>
+ <string name="app_label" msgid="4811759950673118541">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ຂອງລະບົບ"</string>
<string name="status_bar_clear_all_button" msgid="2491321682873657397">"ລຶບ"</string>
<string name="status_bar_no_notifications_title" msgid="7812479124981107507">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
<string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"ດຳເນີນຢູ່"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ປິດຮູບໜ້າຈໍ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ຕົວຢ່າງຮູບໜ້າຈໍ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ເລີ່ມການບັນທຶກບໍ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ໃນລະຫວ່າງການບັນທຶກ, ລະບົບ Android ຈະສາມາດບັນທຶກຂໍ້ມູນທີ່ລະອຽດອ່ອນໃດກໍຕາມທີ່ສະແດງຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນທ່ານ. ນີ້ຮວມເຖິງລະຫັດຜ່ານ, ຂໍ້ມູນການຈ່າຍເງິນ, ຮູບ, ຂໍ້ຄວາມ ແລະ ສຽງນຳ."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ລຶບລ້າງທັງໝົດ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ຈັດການ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ປະຫວັດ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ຂາເຂົ້າ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ການແຈ້ງເຕືອນແບບງຽບ"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"ການແຈ້ງເຕືອນການເຕືອນ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ການສົນທະນາ"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ແຕະເພື່ອຣີສະຕາດແອັບນີ້ ແລະ ໃຊ້ແບບເຕັມຈໍ."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"ການຕັ້ງຄ່າສຳລັບຟອງ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ລົ້ນ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ເພີ່ມກັບໄປຫາການວາງຊ້ອນກັນ"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ຈັດການ"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g> ແລະ ອີກ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ບໍ່ສາມາດໂຫຼດລາຍຊື່ການຄວບຄຸມທັງໝົດໄດ້."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ເພີ່ມໃສ່ການຄວບຄຸມອຸປະກອນ"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ເພີ່ມໃສ່ລາຍການທີ່ມັກ"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ແນະນຳການຄວບຄຸມນີ້ເພື່ອເພີ່ມໃສ່ລາຍການທີ່ທ່ານມັກ."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ເພີ່ມ"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"ແນະນຳໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ອັບເດດການຄວບຄຸມແລ້ວ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ປະກອບມີຕົວອັກສອນ ຫຼື ສັນຍາລັກ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"ຢັ້ງຢືນ <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index fd75874..4f016d3 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Praleisti ekrano kopiją"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrano kopijos peržiūra"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Pradėti įrašymą?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Įrašant „Android“ sistema gali fiksuoti bet kokią neskelbtiną informaciją, rodomą ekrane ar leidžiamą įrenginyje. Tai apima slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir garso įrašus."</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Viską išvalyti"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Tvarkyti"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gaunami"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Tylieji pranešimai"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Įspėjamieji pranešimai"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Pokalbiai"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Palieskite, kad paleistumėte iš naujo šią programą arba įjungtumėte viso ekrano režimą."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ burbulų nustatymai"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Perpildymas"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Pridėti atgal į krūvą"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Tvarkyti"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“ ir dar <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nepavyko įkelti visų valdiklių sąrašo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Pridėjimas prie įrenginio valdiklių"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Pridėjimas prie mėgstamiausių"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"„<xliff:g id="APP">%s</xliff:g>“ pasiūlė pridėti šį valdiklį prie mėgstamiausių."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridėti"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Siūlo „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Valdikliai atnaujinti"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodą sudaro raidės arba simboliai"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> patvirtinimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index d708e5b..5cc696c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Nerādīt ekrānuzņēmumu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrānuzņēmuma priekšskatījums"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Vai sākt ierakstīšanu?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Ierakstīšanas laikā Android sistēmā var tikt tverta jebkura sensitīvā informācija, kas ir redzama jūsu ekrānā vai tiek atskaņota jūsu ierīcē. Šī informācija ir paroles, maksājumu informācija, fotoattēli, ziņojumi un audio."</string>
@@ -512,6 +513,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Dzēst visu"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Pārvaldīt"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Vēsture"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Ienākošie"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Klusie paziņojumi"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Paziņojumi ar skaņu vai vibrāciju"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Sarunas"</string>
@@ -992,6 +994,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Nav nosaukuma"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Pieskarieties, lai restartētu šo lietotni un pārietu pilnekrāna režīmā."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> burbuļu iestatījumi"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Pārpilde"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Pievienot atpakaļ kopai"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Pārvaldīt"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes “<xliff:g id="APP_NAME">%2$s</xliff:g>” un vēl <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1037,8 +1041,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nevarēja ielādēt sarakstu ar visām vadīklām."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Pievienošana ierīču vadīklām"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Pievienot izlasei"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ieteica pievienot šo vadīklu izlasei."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Pievienot"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Ieteica: <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Vadīklas atjauninātas"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ietver burtus vai simbolus."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifikācija: <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 9012b41..64f614f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Отфрлете ја сликата од екранот"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед на слика од екранот"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач на екран"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Да се започне со снимање?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"При снимањето, системот Android може да ги сними сите чувствителни податоци што се видливи на вашиот екран или пуштени на уредот. Ова вклучува лозинки, податоци за плаќање, фотографии, пораки и аудио."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Управувајте"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Дојдовни"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Тивки известувања"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Известувања за предупредување"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Допрете за да ја рестартирате апликацијава и да ја отворите на цел екран."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Поставки за балончињата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Прелевање"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Додајте назад во stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Управување"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g> и уште <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не можеше да се вчита списокот со сите контроли."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друга"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Додајте во контроли за уредите"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Додај во омилени"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> предложи да ја додадете контролава во вашите омилени."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Предложено од <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите се ажурирани"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-кодот содржи букви или симболи"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Потврдете го <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 8581a65..bee7e91 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"സ്ക്രീൻഷോട്ട് ഡിസ്മിസ് ചെയ്യുക"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"സ്ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"റെക്കോർഡിംഗ് ആരംഭിക്കണോ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"റെക്കോർഡ് ചെയ്യുമ്പോൾ, നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ഉപകരണത്തിൽ പ്ലേ ചെയ്യുന്നതോ ആയ ഏത് തന്ത്രപ്രധാന വിവരങ്ങളും Android സിസ്റ്റത്തിന് പകർത്താനാവും. പാസ്വേഡുകൾ, പേയ്മെന്റ് വിവരം, ഫോട്ടോകൾ, സന്ദേശങ്ങൾ, ഓഡിയോ എന്നിവ ഇതിൽ ഉൾപ്പെടുന്നു."</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"അറിയിപ്പ് നിരസിച്ചു."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ബബ്ൾ ഡിസ്മിസ് ചെയ്തു."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"അറിയിപ്പ് ഷെയ്ഡ്."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ദ്രുത ക്രമീകരണങ്ങൾ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ലോക്ക് സ്ക്രീൻ."</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"എല്ലാം മായ്ക്കുക"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"മാനേജ് ചെയ്യുക"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ചരിത്രം"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ഇൻകമിംഗ്"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"നിശബ്ദ അറിയിപ്പുകൾ"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"മുന്നറിയിപ്പ് നൽകുന്ന അറിയിപ്പുകൾ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"സംഭാഷണങ്ങൾ"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ഈ ആപ്പ് റീസ്റ്റാർട്ട് ചെയ്യാനും പൂർണ്ണ സ്ക്രീനാവാനും ടാപ്പ് ചെയ്യുക."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബബിളുകളുടെ ക്രമീകരണം"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ഓവർഫ്ലോ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"അടുക്കുകളിലേക്ക് തിരിച്ച് ചേർക്കുക"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"മാനേജ് ചെയ്യുക"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> കൂടുതലും"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"പവർ മെനുവിൽ നിന്ന് ആക്സസ് ചെയ്യേണ്ട നിയന്ത്രണങ്ങൾ തിരഞ്ഞെടുക്കുക"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"നിയന്ത്രണങ്ങൾ പുനഃക്രമീകരിക്കാൻ പിടിച്ച് വലിച്ചിടുക"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"എല്ലാ നിയന്ത്രണങ്ങളും നീക്കം ചെയ്തു"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"മാറ്റങ്ങൾ സംരക്ഷിച്ചിട്ടില്ല"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"എല്ലാ നിയന്ത്രണങ്ങളുടെയും ലിസ്റ്റ് ലോഡ് ചെയ്യാനായില്ല."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"മറ്റുള്ളവ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ഉപകരണ നിയന്ത്രണങ്ങളിലേക്ക് ചേർക്കുക"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"പ്രിയപ്പെട്ടവയിലേക്ക് ചേർക്കുക"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"ഈ നിയന്ത്രണത്തെ നിങ്ങളുടെ പ്രിയപ്പെട്ടവയിലേക്ക് ചേർക്കാൻ <xliff:g id="APP">%s</xliff:g> ശുപാർശ ചെയ്തു."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ചേർക്കുക"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> നിർദ്ദേശിച്ചത്"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"നിയന്ത്രണങ്ങൾ അപ്ഡേറ്റ് ചെയ്തു"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"പിന്നിൽ അക്ഷരങ്ങളോ ചിഹ്നങ്ങളോ അടങ്ങിയിരിക്കുന്നു"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> പരിശോധിച്ചുറപ്പിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4a3a5cd..9e915e0 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -45,7 +45,7 @@
<string name="status_bar_settings_notifications" msgid="5285316949980621438">"Мэдэгдэл"</string>
<string name="bluetooth_tethered" msgid="4171071193052799041">"Блютүүтыг модем болгож байна"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"Оруулах аргыг тохируулах"</string>
- <string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"Бодит гар"</string>
+ <string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"Биет гар"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g>-г <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>-д <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?\nЭнэ аппад бичих зөвшөөрөл олгогдоогүй ч USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string>
<string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="APPLICATION">%1$s</xliff:g>-г <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Дэлгэцийн агшныг хаах"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Дэлгэцийн агшныг урьдчилан үзэх"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн үйлдэл бичигч"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Бичлэгийг эхлүүлэх үү?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, зурвас болон аудио багтана."</string>
@@ -297,8 +298,8 @@
<string name="accessibility_quick_settings_flashlight_on" msgid="3785616827729850766">"Флаш гэрэл ассан."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3782375441381402599">"Флаш гэрлийг унтраасан."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="4747870681508334200">"Флаш гэрлийг асаасан."</string>
- <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"Өнгө урвуулагчийг унтраасан."</string>
- <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"Өнгө урвуулагчийг асаасан."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"Өнгө хувиргалтыг унтраасан."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"Өнгө хувиргалтыг асаасан."</string>
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Мобайл хотспотыг унтраасан."</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Мобайл хотспотыг асаасан."</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Дэлгэц дамжуулалт зогссон."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Удирдах"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Түүх"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Ирж буй"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Чимээгүй мэдэгдэл"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Сэрэмжлүүлэх мэдэгдэл"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Харилцан яриа"</string>
@@ -691,7 +693,7 @@
<string name="notification_channel_unsilenced" msgid="94878840742161152">"Эдгээр мэдэгдлийг танд мэдэгдэнэ"</string>
<string name="inline_blocking_helper" msgid="2891486013649543452">"Та эдгээр мэдэгдлийг ихэвчлэн хаадаг. \nЭдгээрийг харуулсан хэвээр байх уу?"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Болсон"</string>
- <string name="inline_ok_button" msgid="603075490581280343">"Хаах"</string>
+ <string name="inline_ok_button" msgid="603075490581280343">"Ашиглах"</string>
<string name="inline_keep_showing" msgid="8736001253507073497">"Эдгээр мэдэгдлийг харуулсан хэвээр байх уу?"</string>
<string name="inline_stop_button" msgid="2453460935438696090">"Мэдэгдлийг зогсоох"</string>
<string name="inline_deliver_silently_button" msgid="2714314213321223286">"Дуугүй хүргэх"</string>
@@ -708,7 +710,7 @@
<string name="notification_alert_title" msgid="7629202599338071971">"Дуутай"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Бөмбөлөг"</string>
<string name="notification_channel_summary_low" msgid="7300447764759926720">"Дуу эсвэл чичиргээгүйгээр танд төвлөрөхөд тусална."</string>
- <string name="notification_channel_summary_default" msgid="3539949463907902037">"Дуу эсвэл чичиргээгүйгээр таны анхаарлыг татна."</string>
+ <string name="notification_channel_summary_default" msgid="3539949463907902037">"Дуу эсвэл чичиргээгээр таны анхаарлыг татна."</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="6298026344552480458">"Дуу эсвэл чичиргээгээр таны анхаарлыг татна. <xliff:g id="APP_NAME">%1$s</xliff:g>-н харилцан яриаг өгөгдмөл тохиргоогоор бөмбөлөг болгоно."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Энэ контентын хөвөн гарч ирэх товчлолтойгоор таны анхаарлыг татдаг."</string>
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Харилцан ярианы хэсгийн дээд талд, бөмбөлөг хэлбэрээр харагдана."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Энэ аппыг дахин эхлүүлж, бүтэн дэлгэцэд орохын тулд товшино уу."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н бөмбөлгүүдийн тохиргоо"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Халих"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Өрөлтөд буцааж нэмэх"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Удирдах"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бүх хяналтын жагсаалтыг ачаалж чадсангүй."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Төхөөрөмжийн хяналт руу нэмэх"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Дуртайд нэмэх"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> нь энэ хяналтыг дуртайдаа нэмэхийг санал болгосон."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Нэмэх"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>-н санал болгосон"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Хяналтуудыг шинэчиллээ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН нь үсэг эсвэл дүрс тэмдэгт агуулдаг"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>-г бататгах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 530dbfb..d0730c0 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -22,7 +22,7 @@
<string name="app_label" msgid="4811759950673118541">"सिस्टम UI"</string>
<string name="status_bar_clear_all_button" msgid="2491321682873657397">"साफ करा"</string>
<string name="status_bar_no_notifications_title" msgid="7812479124981107507">"सूचना नाहीत"</string>
- <string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"सुरु असलेले"</string>
+ <string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"सुरू असलेले"</string>
<string name="status_bar_latest_events_title" msgid="202755896454005436">"सूचना"</string>
<string name="battery_low_title" msgid="6891106956328275225">"बॅटरी लवकर संपू शकते"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक"</string>
@@ -35,7 +35,7 @@
<string name="battery_low_why" msgid="2056750982959359863">"सेटिंग्ज"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"बॅटरी सेव्हर सुरू करायचा का?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"बॅटरी सेव्हर बाबत"</string>
- <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"चालू करा"</string>
+ <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"सुरू करा"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"बॅटरी सेव्हर सुरू करा"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"सेटिंग्ज"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"वाय-फाय"</string>
@@ -62,7 +62,7 @@
<string name="usb_debugging_always" msgid="4003121804294739548">"या संगणकावरून नेहमी अनुमती द्या"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"अनुमती द्या"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB डीबग करण्यास अनुमती नाही"</string>
- <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"सध्या या डीव्हाइसमध्ये साइन इन केलेला वापरकर्ता USB डीबग करणे चालू करू शकत नाही. हे वैशिष्ट्य वापरण्यासाठी, प्राथमिक वापरकर्त्यावर स्विच करा."</string>
+ <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"सध्या या डीव्हाइसमध्ये साइन इन केलेला वापरकर्ता USB डीबग करणे सुरू करू शकत नाही. हे वैशिष्ट्य वापरण्यासाठी, प्राथमिक वापरकर्त्यावर स्विच करा."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"या नेटवर्कवर वायरलेस डीबगिंग करण्याला अनुमती द्यायची का?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्कचे नाव (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nवाय-फाय ॲड्रेस (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"या नेटवर्कवर नेहमी अनुमती द्या"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"स्क्रीनशॉट डिसमिस करा"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉटचे पूर्वावलोकन"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"रेकॉर्डिंग सुरू करायचे आहे का?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"रेकॉर्डिंग करताना, Android सिस्टम तुमच्या स्क्रीनवर दिसणारी किंवा तुमच्या डिव्हाइसवर प्ले केलेली कोणतीही संवेदनशील माहिती कॅप्चर करू शकते. यात पासवर्ड, पेमेंट माहिती, फोटो, मेसेज आणि ऑडिओचा समावेश आहे."</string>
@@ -209,7 +210,7 @@
<string name="accessibility_two_bars" msgid="1335676987274417121">"दोन बार."</string>
<string name="accessibility_three_bars" msgid="819417766606501295">"तीन बार."</string>
<string name="accessibility_signal_full" msgid="5920148525598637311">"सिग्नल पूर्ण."</string>
- <string name="accessibility_desc_on" msgid="2899626845061427845">"चालू."</string>
+ <string name="accessibility_desc_on" msgid="2899626845061427845">"सुरू."</string>
<string name="accessibility_desc_off" msgid="8055389500285421408">"बंद."</string>
<string name="accessibility_desc_connected" msgid="3082590384032624233">"कनेक्ट केले."</string>
<string name="accessibility_desc_connecting" msgid="8011433412112903614">"कनेक्ट करत आहे."</string>
@@ -234,7 +235,7 @@
<string name="cell_data_off" msgid="4886198950247099526">"बंद"</string>
<string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"ब्लूटूथ टेदरिंग."</string>
<string name="accessibility_airplane_mode" msgid="1899529214045998505">"विमान मोड."</string>
- <string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN चालू."</string>
+ <string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN सुरू."</string>
<string name="accessibility_no_sims" msgid="5711270400476534667">"सिम कार्ड नाही."</string>
<string name="carrier_network_change_mode" msgid="5174141476991149918">"वाहक नेटवर्क बदलत आहे"</string>
<string name="accessibility_battery_details" msgid="6184390274150865789">"बॅटरी तपशील उघडा"</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना डिसमिस केल्या."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"बबल डिसमिस केला."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिंग्ज."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
@@ -266,13 +266,13 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करा"</string>
<string name="accessibility_quick_settings_wifi" msgid="167707325133803052">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
<string name="accessibility_quick_settings_wifi_changed_off" msgid="2230487165558877262">"Wifi बंद झाले."</string>
- <string name="accessibility_quick_settings_wifi_changed_on" msgid="1490362586009027611">"Wifi चालू झाले."</string>
+ <string name="accessibility_quick_settings_wifi_changed_on" msgid="1490362586009027611">"Wifi सुरू झाले."</string>
<string name="accessibility_quick_settings_mobile" msgid="1817825313718492906">"मोबाईल <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
<string name="accessibility_quick_settings_battery" msgid="533594896310663853">"बॅटरी <xliff:g id="STATE">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_airplane_off" msgid="1275658769368793228">"विमान मोड बंद."</string>
- <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"विमान मोड चालू."</string>
+ <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"विमान मोड सुरू."</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"विमान मोड बंद केला."</string>
- <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"विमान मोड चालू केला."</string>
+ <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"विमान मोड सुरू केला."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"संपूर्ण शांतता"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"फक्त अलार्म"</string>
<string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"व्यत्यय आणू नका."</string>
@@ -280,35 +280,35 @@
<string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"व्यत्यय आणू नका सुरू केले आहे."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ब्लूटूथ."</string>
<string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"ब्लूटूथ बंद."</string>
- <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ब्लूटूथ चालू."</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ब्लूटूथ सुरू."</string>
<string name="accessibility_quick_settings_bluetooth_connecting" msgid="7362294657419149294">"ब्लूटूथ कनेक्ट करत आहे."</string>
<string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"ब्लूटूथ कनेक्ट केले."</string>
<string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"ब्लूटूथ बंद केले."</string>
- <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"ब्लूटूथ चालू केले."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"ब्लूटूथ सुरू केले."</string>
<string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"स्थान अहवाल बंद."</string>
- <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"स्थान अहवाल चालू."</string>
+ <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"स्थान अहवाल सुरू."</string>
<string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"स्थान अहवाल बंद केला."</string>
- <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"स्थान अहवाल चालू केला."</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"स्थान अहवाल सुरू केला."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> साठी अलार्म सेट केला."</string>
<string name="accessibility_quick_settings_close" msgid="2974895537860082341">"पॅनेल बंद करा."</string>
<string name="accessibility_quick_settings_more_time" msgid="7646479831704665284">"अधिक वेळ."</string>
<string name="accessibility_quick_settings_less_time" msgid="9110364286464977870">"कमी वेळ."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="7606563260714825190">"फ्लॅशलाइट बंद."</string>
<string name="accessibility_quick_settings_flashlight_unavailable" msgid="7458591827288347635">"फ्लॅशलाइट अनुपलब्ध आहे."</string>
- <string name="accessibility_quick_settings_flashlight_on" msgid="3785616827729850766">"फ्लॅशलाइट चालू."</string>
+ <string name="accessibility_quick_settings_flashlight_on" msgid="3785616827729850766">"फ्लॅशलाइट सुरू."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3782375441381402599">"फ्लॅशलाइट बंद केला."</string>
- <string name="accessibility_quick_settings_flashlight_changed_on" msgid="4747870681508334200">"फ्लॅशलाइट चालू केला."</string>
+ <string name="accessibility_quick_settings_flashlight_changed_on" msgid="4747870681508334200">"फ्लॅशलाइट सुरू केला."</string>
<string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"रंग उत्क्रमण बंद केले."</string>
- <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"रंग उत्क्रमण चालू केले."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"रंग उत्क्रमण सुरू केले."</string>
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"मोबाईल हॉटस्पॉट बंद केला."</string>
- <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"मोबाईल हॉटस्पॉट चालू केला."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"मोबाईल हॉटस्पॉट सुरू केला."</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"स्क्रीन कास्ट करणे थांबले."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="562749867895549696">"कार्य मोड बंद."</string>
- <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"कार्य मोड चालू."</string>
+ <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"कार्य मोड सुरू."</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="6256690740556798683">"कार्य मोड बंद केला."</string>
- <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"कार्य मोड चालू केला."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"कार्य मोड सुरू केला."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"डेटा सर्व्हर बंद केला."</string>
- <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"डेटा सर्व्हर चालू केला."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"डेटा सर्व्हर सुरू केला."</string>
<string name="accessibility_quick_settings_sensor_privacy_changed_off" msgid="7608378211873807353">"सेन्सर गोपनीयता बंद केली आहे."</string>
<string name="accessibility_quick_settings_sensor_privacy_changed_on" msgid="4267393685085328801">"सेन्सर गोपनीयता सुरू केली आहे."</string>
<string name="accessibility_brightness" msgid="5391187016177823721">"डिस्प्ले चमक"</string>
@@ -318,7 +318,7 @@
<string name="data_usage_disabled_dialog_mobile_title" msgid="2286843518689837719">"मोबाइल डेटा थांबवला आहे"</string>
<string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"डेटास विराम दिला आहे"</string>
<string name="data_usage_disabled_dialog" msgid="7933201635215099780">"तुम्ही सेट केलेली डेटा मर्यादा संपली. आता तुमचे मोबाइल डेटा वापरणे बंद आहे.\n\nतुम्ही ते पुन्हा सुरू केल्यास, डेटा वापरासाठी शुल्क लागू होईल."</string>
- <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"पुन्हा सुरु करा"</string>
+ <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"पुन्हा सुरू करा"</string>
<string name="gps_notification_searching_text" msgid="231304732649348313">"GPS शोधत आहे"</string>
<string name="gps_notification_found_text" msgid="3145873880174658526">"GPS द्वारे स्थान सेट केले"</string>
<string name="accessibility_location_active" msgid="2845747916764660369">"स्थान विनंत्या सक्रिय"</string>
@@ -378,7 +378,7 @@
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट केले नाही"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क नाही"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"वाय-फाय बंद"</string>
- <string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"वाय-फाय चालू"</string>
+ <string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"वाय-फाय सुरू"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"वाय-फाय नेटवर्क उपलब्ध नाहीत"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"सुरू करत आहे…"</string>
<string name="quick_settings_cast_title" msgid="2279220930629235211">"स्क्रीन कास्ट करा"</string>
@@ -416,9 +416,9 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
<string name="quick_settings_work_mode_label" msgid="2754212289804324685">"कार्य प्रोफाइल"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"रात्रीचा प्रकाश"</string>
- <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"संध्याकाळी चालू असते"</string>
+ <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"संध्याकाळी सुरू असते"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयापर्यंत"</string>
- <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> वाजता चालू"</string>
+ <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> वाजता सुरू"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> पर्यंत"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"गडद थीम"</string>
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"बॅटरी सेव्हर"</string>
@@ -480,9 +480,9 @@
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"काढा"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्हा स्वागत आहे!"</string>
- <string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरु ठेवू इच्छिता?"</string>
+ <string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string>
- <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"होय, सुरु ठेवा"</string>
+ <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"होय, सुरू ठेवा"</string>
<string name="guest_notification_title" msgid="4434456703930764167">"अतिथी वापरकर्ता"</string>
<string name="guest_notification_text" msgid="4202692942089571351">"अॅप्स आणि डेटा हटविण्यासाठी, अतिथी वापरकर्ता काढा"</string>
<string name="guest_notification_remove_action" msgid="4153019027696868099">"अतिथी काढा"</string>
@@ -510,8 +510,9 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"आलेल्या"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"सायलंट सूचना"</string>
- <string name="notification_section_header_alerting" msgid="3168140660646863240">"लक्ष वेधून घेणाऱ्या सूचना"</string>
+ <string name="notification_section_header_alerting" msgid="3168140660646863240">"इशारा देणाऱ्या सूचना"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"संभाषणे"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सर्व सायलंट सूचना साफ करा"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"व्यत्यय आणून नकाद्वारे सूचना थांबवल्या"</string>
@@ -549,7 +550,7 @@
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"आपल्या संस्थेने या डिव्हाइसवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"आपल्या संस्थेने आपल्या कार्य प्रोफाइलवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"या डिव्हाइसवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
- <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"आपल्या प्रशासकाने नेटवर्क लॉगिंग चालू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे परीक्षण करते."</string>
+ <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"आपल्या प्रशासकाने नेटवर्क लॉगिंग सुरू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे परीक्षण करते."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"तुम्ही <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अॅप्स आणि वेबसाइटसहित आपल्या नेटवर्क क्रिया मॉनिटर करू शकते."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"तुम्ही <xliff:g id="VPN_APP_0">%1$s</xliff:g> आणि <xliff:g id="VPN_APP_1">%2$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अॅप्स आणि वेबसाइटसहित आपल्या नेटवर्क क्रिया मॉनिटर करू शकते."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"तुमचे कार्य प्रोफाइल <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
@@ -564,7 +565,7 @@
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN सेटिंग्ज उघडा"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"विश्वासू क्रेडेंशियल उघडा"</string>
- <string name="monitoring_description_network_logging" msgid="577305979174002252">"आपल्या प्रशासकाने नेटवर्क लॉगिंग चालू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
+ <string name="monitoring_description_network_logging" msgid="577305979174002252">"आपल्या प्रशासकाने नेटवर्क लॉगिंग सुरू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"तुम्ही VPN कनेक्शन सेट करण्यासाठी अॅपला परवानगी दिली.\n\nहा अॅप ईमेल, अॅप्स आणि वेबसाइटसह, तुमच्या डिव्हाइस आणि नेटवर्क ॲक्टिव्हिटीचे परीक्षण करू शकतो."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nतुमचा प्रशासक ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करू शकते."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
@@ -605,7 +606,7 @@
<string name="screen_pinning_start" msgid="5695091877402422575">"स्क्रीन पिन केला"</string>
<string name="screen_pinning_exit" msgid="5114993350662745840">"स्क्रीन अनपिन केला"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
- <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"तुम्ही सेटिंग्जमध्ये ते पुढील वेळी चालू कराल तेव्हा ते पुन्हा दिसेल."</string>
+ <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"तुम्ही सेटिंग्जमध्ये ते पुढील वेळी सुरू कराल तेव्हा ते पुन्हा दिसेल."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"लपवा"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"कॉल करा"</string>
<string name="stream_system" msgid="7663148785370565134">"सिस्टम"</string>
@@ -635,7 +636,7 @@
<string name="output_title" msgid="3938776561655668350">"मीडिया आउटपुट"</string>
<string name="output_calls_title" msgid="7085583034267889109">"फोन कॉल आउटपुट"</string>
<string name="output_none_found" msgid="5488087293120982770">"कोणतीही डिव्हाइस सापडली नाहीत"</string>
- <string name="output_none_found_service_off" msgid="935667567681386368">"कोणतीही डिव्हाइस सापडली नाहीत. <xliff:g id="SERVICE">%1$s</xliff:g> चालू करून पाहा"</string>
+ <string name="output_none_found_service_off" msgid="935667567681386368">"कोणतीही डिव्हाइस सापडली नाहीत. <xliff:g id="SERVICE">%1$s</xliff:g> सुरू करून पाहा"</string>
<string name="output_service_bt" msgid="4315362133973911687">"ब्लूटूथ"</string>
<string name="output_service_wifi" msgid="9003667810868222134">"वाय-फाय"</string>
<string name="output_service_bt_wifi" msgid="7186882540475524124">"ब्लूटूथ आणि वाय-फाय"</string>
@@ -662,7 +663,7 @@
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"हॉटस्पॉट"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाईल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"सर्वांसाठी नाही तर काहींसाठी मजेदार असू शकते"</string>
- <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्याला Android वापरकर्ता इंटरफेस ट्विक आणि कस्टमाइझ करण्याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्यातील रिलीज मध्ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरु ठेवा."</string>
+ <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्याला Android वापरकर्ता इंटरफेस ट्विक आणि कस्टमाइझ करण्याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्यातील रिलीज मध्ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"ही प्रयोगात्मक वैशिष्ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्यातील रिलीज मध्ये कदाचित दिसणार नाहीत."</string>
<string name="got_it" msgid="477119182261892069">"समजले"</string>
<string name="tuner_toast" msgid="3812684836514766951">"अभिनंदन! सिस्टम UI ट्युनर सेटिंग्जमध्ये जोडले गेले आहे"</string>
@@ -675,14 +676,14 @@
<string name="show_brightness" msgid="6700267491672470007">"द्रुत सेटिंग्जमध्ये चमक दर्शवा"</string>
<string name="experimental" msgid="3549865454812314826">"प्रायोगिक"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"ब्लूटूथ सुरू करायचे?"</string>
- <string name="enable_bluetooth_message" msgid="6740938333772779717">"तुमचा कीबोर्ड तुमच्या टॅबलेटसह कनेक्ट करण्यासाठी, तुम्ही प्रथम ब्लूटूथ चालू करणे आवश्यक आहे."</string>
- <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"चालू करा"</string>
+ <string name="enable_bluetooth_message" msgid="6740938333772779717">"तुमचा कीबोर्ड तुमच्या टॅबलेटसह कनेक्ट करण्यासाठी, तुम्ही प्रथम ब्लूटूथ सुरू करणे आवश्यक आहे."</string>
+ <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"सुरू करा"</string>
<string name="show_silently" msgid="5629369640872236299">"सूचना शांतपणे दर्शवा"</string>
<string name="block" msgid="188483833983476566">"सर्व सूचना ब्लॉक करा"</string>
<string name="do_not_silence" msgid="4982217934250511227">"शांत करू नका"</string>
<string name="do_not_silence_block" msgid="4361847809775811849">"शांत किंवा अवरोधित करू नका"</string>
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"पॉवर सूचना नियंत्रणे"</string>
- <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"चालू"</string>
+ <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"सुरू"</string>
<string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"बंद"</string>
<string name="power_notification_controls_description" msgid="1334963837572708952">"पॉवर सूचना नियंत्रणांच्या साहाय्याने तुम्ही अॅप सूचनांसाठी 0 ते 5 असे महत्त्व स्तर सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दाखवा \n- फुल स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>\n" - फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा व्हायब्रेट करू नका \n\n"<b>"स्तर 1"</b>\n"- फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा व्हायब्रेट करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना ब्लॉक करा"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"सूचना"</string>
@@ -918,7 +919,7 @@
<string name="pip_skip_to_prev" msgid="3742589641443049237">"डावलून मागे जा"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"तापल्यामुळे फोन बंद झाला"</string>
<string name="thermal_shutdown_message" msgid="7432744214105003895">"तुमचा फोन आता व्यवस्थित सुरू आहे"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"तुमचा फोन खूप तापलाय, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा फोन आता व्यवस्थित सुरू आहे.\n\nतुम्ही असे केल्यास तुमचा फोन खूप तापेल:\n •संसाधन केंद्रित अॅप वापरणे (गेमिंग, व्हिडिओ किंवा नेव्हिगेशन अॅप यासारखे)\n •मोठ्या फायली डाउनलोड किंवा अपलोड करणे\n •उच्च तापमानामध्ये तुमचा फोन वापरणे"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"तुमचा फोन खूप तापलाय, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा फोन आता व्यवस्थित सुरू आहे.\n\nतुम्ही असे केल्यास तुमचा फोन खूप तापेल:\n •संसाधन केंद्रित अॅप वापरणे (गेमिंग, व्हिडिओ किंवा नेव्हिगेशन अॅप यासारखे)\n •मोठ्या फाइल डाउनलोड किंवा अपलोड करणे\n •उच्च तापमानामध्ये तुमचा फोन वापरणे"</string>
<string name="high_temp_title" msgid="2218333576838496100">"फोन ऊष्ण होत आहे"</string>
<string name="high_temp_notif_message" msgid="163928048626045592">"फोन थंड होत असताना काही वैशिष्ट्ये मर्यादित असतात"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
@@ -957,9 +958,9 @@
<string name="wifi_is_off" msgid="5389597396308001471">"वाय-फाय बंद आहे"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ब्लूटूथ बंद आहे"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"व्यत्यय आणू नका बंद आहे"</string>
- <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"व्यत्यय आणू नका एका <xliff:g id="ID_1">%s</xliff:g> स्वयंचलित नियमाने चालू केले."</string>
- <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"व्यत्यय आणू नका (<xliff:g id="ID_1">%s</xliff:g>) ॲपने चालू केले."</string>
- <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"व्यत्यय आणू नका एका स्वयंचलित नियमाने किंवा ॲपने चालू केले."</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"व्यत्यय आणू नका एका <xliff:g id="ID_1">%s</xliff:g> स्वयंचलित नियमाने सुरू केले."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"व्यत्यय आणू नका (<xliff:g id="ID_1">%s</xliff:g>) ॲपने सुरू केले."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"व्यत्यय आणू नका एका स्वयंचलित नियमाने किंवा ॲपने सुरू केले."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> पर्यंत"</string>
<string name="qs_dnd_keep" msgid="3829697305432866434">"ठेवा"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"पुनर्स्थित करा"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक नाही"</string>
<string name="restart_button_description" msgid="6916116576177456480">"हे अॅप रीस्टार्ट करण्यासाठी आणि फुल स्क्रीन करण्यासाठी टॅप करा."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबलसाठी सेटिंग्ज"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ओव्हरफ्लो"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"स्टॅकमध्ये परत जोडा"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"व्यवस्थापित करा"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> कडून <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> आणि आणखी <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> कडून <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"पॉवर मेनूमधून अॅक्सेस करण्यासाठी नियंत्रणे निवडा"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"नियंत्रणांची पुनर्रचना करण्यासाठी धरून ठेवा आणि ड्रॅग करा"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"सर्व नियंत्रणे काढून टाकली आहेत"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"बदल सेव्ह केले गेले नाहीत"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"सर्व नियंत्रणांची सूची लोड करता आली नाही."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"इतर"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"डिव्हाइस नियंत्रणांमध्ये जोडा"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"आवडीचे यामध्ये जोडा"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ने तुमच्या आवडीचे मध्ये जोडण्यासाठी या नियंत्रणाची शिफारस केली आहे."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"जोडा"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ने सुचवले आहे"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"नियंत्रणे अपडेट केली आहेत"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरांचा किंवा चिन्हांचा समावेश असतो"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ची पडताळणी करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 482d608..94b5ad3 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ketepikan tangkapan skrin"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pratonton tangkapan skrin"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Perakam Skrin"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses rakaman skrin"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pemberitahuan breterusan untuk sesi rakaman skrin"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Mula Merakam?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Semasa merakam, Sistem Android dapat menangkap mana-mana maklumat sensitif yang kelihatan pada skrin anda atau yang dimainkan pada peranti anda. Ini termasuklah kata laluan, maklumat pembayaran, foto, mesej dan audio."</string>
@@ -388,7 +389,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi tidak disambungkan"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"AUTO"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Terbalikkan warna"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Songsangkan warna"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Mod pembetulan warna"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Lagi tetapan"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Kosongkan semua"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Urus"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Sejarah"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Masuk"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Pemberitahuan senyap"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Pemberitahuan memaklumi"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Perbualan"</string>
@@ -584,7 +586,7 @@
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Tetapan bunyi"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"Kembangkan"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"Runtuhkan"</string>
- <string name="volume_odi_captions_tip" msgid="8825655463280990941">"Kapsyen media automatik"</string>
+ <string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sari kata media automatik"</string>
<string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"Petua sari kata"</string>
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Tindanan kapsyen"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"dayakan"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Tiada tajuk"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Ketik untuk memulakan semula apl ini dan menggunakan skrin penuh."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Tetapan untuk gelembung <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Limpahan"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Tambah kembali pada tindanan"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Urus"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> lagi"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Senarai semua kawalan tidak dapat dimuatkan."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan pada kawalan peranti"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Tambahkan pada kegemaran"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> mencadangkan kawalan ini untuk ditambahkan pada kegemaran anda."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambah"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Dicadangkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kawalan dikemas kini"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN mengandungi huruf atau simbol"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Sahkan <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 6366acb..58160fc 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ဖန်သားပြင်ဓာတ်ပုံ ပယ်ရန်"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ဖန်သားပြင်ဓာတ်ပုံ အစမ်းကြည့်ရှုခြင်း"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ဖန်သားပြင် ရိုက်ကူးမှု"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ဖန်သားပြင်ရိုက်ကူးနေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"စတင် ရိုက်ကူးမလား။"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ရိုက်ကူးနေစဉ်အတွင်း Android စနစ်သည် သင့်မျက်နှာပြင်ပေါ်တွင် မြင်နိုင်သော သို့မဟုတ် သင့်စက်ပစ္စည်းတွင် ဖွင့်ထားသော အရေးကြီးသည့် အချက်အလက်မှန်သမျှကို ရိုက်ကူးနိုင်သည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှု အချက်အလက်၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် အသံများ ပါဝင်သည်။"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံး ဖယ်ရှားရန်"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"အဝင်"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"အကြောင်းကြားချက်များကို အသံတိတ်ခြင်း"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"အကြောင်းကြားချက်များကို သတိပေးခြင်း"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"စကားဝိုင်းများ"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ဤအက်ပ်ကို ပြန်စတင်ပြီး မျက်နှာပြင်အပြည့်လုပ်ရန် တို့ပါ။"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပူဖောင်းကွက်အတွက် ဆက်တင်များ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"အပိုများပြရန်"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ပူဖေါင်းတန်းသို့ ပြန်ထည့်ရန်"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"စီမံရန်"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> နှင့် နောက်ထပ် <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ခုမှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ထိန်းချုပ်မှုအားလုံး၏ စာရင်းကို ဖွင့်၍မရပါ။"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"စက်ထိန်းစနစ်သို့ ထည့်ရန်"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"အကြိုက်ဆုံးများသို့ ထည့်ရန်"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> သည် ဤခလုတ်ကို သင့်အကြိုက်ဆုံးများသို့ ထည့်ရန် အကြံပြုထားသည်။"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ထည့်ရန်"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> က အကြံပြုထားသည်"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ထိန်းချုပ်မှု အပ်ဒိတ်လုပ်ပြီးပြီ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ပင်နံပါတ်တွင် စာလုံး သို့မဟုတ် သင်္ကေတများပါဝင်သည်"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ကို အတည်ပြုခြင်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3fd742e..0c21879d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Avvis skjermdumpen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning av skjermdump"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Vil du starte opptaket?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Under opptak kan Android-systemet registrere all sensitiv informasjon som er synlig på skjermen eller spilles av på enheten. Dette inkluderer passord, betalingsinformasjon, bilder, meldinger og lyd."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Fjern alt"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Logg"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Innkommende"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Lydløse varsler"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Varsler med varsling"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen tittel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Trykk for å starte denne appen på nytt og vise den i fullskjerm."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Innstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>-bobler"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflyt"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Legg tilbake i stabelen"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Administrer"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> flere"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over alle kontroller kunne ikke lastes inn."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Legg til i enhetsstyring"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Legg til som favoritt"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> har foreslått at du legger denne kontrollen til i favorittene dine."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Legg til"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Foreslått av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollene er oppdatert"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koden inneholder bokstaver eller symboler"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Bekreft <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 6a9fb2a..6a0423c7 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -28,7 +28,7 @@
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी"</string>
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> बाँकी, तपाईंको प्रयोगका आधारमा करिब <xliff:g id="TIME">%2$s</xliff:g> बाँकी छ"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> बाँकी, करिब <xliff:g id="TIME">%2$s</xliff:g> बाँकी छ"</string>
- <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी। ब्याट्री सेभर सक्रिय छ।"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी। ब्याट्री सेभर अन छ ।"</string>
<string name="invalid_charger" msgid="4370074072117767416">"USB मार्फत चार्ज गर्न सकिँदैन। तपाईंको यन्त्रसँगै आएको चार्जर प्रयोग गर्नुहोस्।"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB मार्फत चार्ज गर्न सकिँदैन"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"तपाईंको यन्त्रसँगै आएको चार्जर प्रयोग गर्नुहोस्"</string>
@@ -47,10 +47,10 @@
<string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"इनपुट विधिहरू सेटअप गर्नुहोस्"</string>
<string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"वास्तविक किबोर्ड"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
- <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्न अनुमति दिने हो?\nयो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
+ <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्न अनुमति दिने हो?\nयो एपलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
<string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
<string name="usb_device_confirm_prompt" msgid="4091711472439910809">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> को व्यवस्थापन गर्न <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्ने हो?"</string>
- <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> सञ्चालन गर्न खोल्ने हो?\nयो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
+ <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> सञ्चालन गर्न खोल्ने हो?\nयो एपलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> को व्यवस्थापन गर्न <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्ने हो?"</string>
<string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"यस USB उपकरणसँग स्थापित एप काम गर्दैन। यस उपकरणको बारेमा <xliff:g id="URL">%1$s</xliff:g> मा धेरै जान्नुहोस्"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"USB सहयोगी"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"स्क्रिनसट हटाउनुहोस्"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रिनसटको पूर्वावलोकन"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"रेकर्ड गर्न थाल्ने हो?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"रेकर्ड गर्दा, Android प्रणालीले तपाईंको स्क्रिनमा देखिने वा तपाईंको यन्त्रमा प्ले गरिने सबै संवेदनशील जानकारी रेकर्ड गर्न सक्छ। यो जानकारीमा पासवर्ड, भुक्तानीसम्बन्धी जानकारी, फोटो, सन्देश र अडियो समावेश हुन्छ।"</string>
@@ -194,7 +195,7 @@
<string name="accessibility_data_signal_full" msgid="283507058258113551">"डेटा संकेत पूर्ण।"</string>
<string name="accessibility_wifi_name" msgid="4863440268606851734">"<xliff:g id="WIFI">%s</xliff:g> मा जडित।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
- <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> मा जडान गरियो।"</string>
+ <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> मा कनेक्ट गरियो।"</string>
<string name="accessibility_no_wimax" msgid="2014864207473859228">"वाइम्यास छैन।"</string>
<string name="accessibility_wimax_one_bar" msgid="2996915709342221412">"WiMAX एउटा पट्टि।"</string>
<string name="accessibility_wimax_two_bars" msgid="7335485192390018939">"वाइम्याक्स दुईवटा बारहरू।"</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना खारेज।"</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"बबल हटाइयो।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना कक्ष।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिङहरू"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"स्क्रीन बन्द गर्नुहोस्।"</string>
@@ -499,9 +499,9 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"प्रयोगकर्ता हटाउन चाहनुहुन्छ?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"यस प्रयोगकर्ताको सबै एपहरू तथा डेटा हटाइने छ।"</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"हटाउनुहोस्"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"ब्याट्री सेभर सक्रिय छ"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"ब्याट्री सेभर अन छ"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
- <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ब्याट्री सेभर निष्क्रिय पार्नुहोस्"</string>
+ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ब्याट्री सेभर अफ गर्नुहोस्"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"सबै हटाउनुहोस्"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थित गर्नुहोस्"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"हालसालै प्राप्त भएका सूचनाहरू"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"मौन सूचनाहरू"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"कम्पन वा आवाजसहितका सूचनाहरू"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"वार्तालापहरू"</string>
@@ -581,7 +582,7 @@
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"धन्यवाद पर्दैन"</string>
<string name="hidden_notifications_setup" msgid="2064795578526982467">"सेटअप गर्नुहोस्"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
- <string name="volume_zen_end_now" msgid="5901885672973736563">"अहिले नै निष्क्रिय पार्नुहोस्"</string>
+ <string name="volume_zen_end_now" msgid="5901885672973736563">"अहिले नै अफ गर्नुहोस्"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ध्वनिसम्बन्धी सेटिङहरू"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"विस्तार गर्नुहोस्"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"संक्षिप्त पार्नुहोस्"</string>
@@ -682,7 +683,7 @@
<string name="do_not_silence" msgid="4982217934250511227">"मौन नगर्नुहोस्"</string>
<string name="do_not_silence_block" msgid="4361847809775811849">"मौन नगर्नुहोस् वा नरोक्नुहोस्"</string>
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"सशक्त सूचना नियन्त्रण"</string>
- <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"सक्रिय"</string>
+ <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"अन छ"</string>
<string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"निष्क्रिय"</string>
<string name="power_notification_controls_description" msgid="1334963837572708952">"सशक्त सूचना नियन्त्रणहरू मार्फत तपाईं अनुप्रयाेगका सूचनाहरूका लागि ० देखि ५ सम्मको महत्व सम्बन्धी स्तर सेट गर्न सक्नुहुन्छ। \n\n"<b>"स्तर ५"</b>" \n- सूचनाको सूचीको माथिल्लो भागमा देखाउने \n- पूर्ण स्क्रिनमा अवरोधका लागि अनुमति दिने \n- सधैँ चियाउने \n\n"<b>"स्तर ४"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- सधैँ चियाउने \n\n"<b>"स्तर ३"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n\n"<b>"स्तर २"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने र कम्पन नगर्ने \n\n"<b>"स्तर १"</b>" \n- पूर्ण स्क्रिनमा अवरोध रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने वा कम्पन नगर्ने \n- लक स्क्रिन र वस्तुस्थिति पट्टीबाट लुकाउने \n- सूचनाको सूचीको तल्लो भागमा देखाउने \n\n"<b>"स्तर ०"</b>" \n- अनुप्रयोगका सबै सूचनाहरूलाई रोक्ने"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"सूचनाहरू"</string>
@@ -968,7 +969,7 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा निष्क्रिय पार्ने हो?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"तपाईं <xliff:g id="CARRIER">%s</xliff:g> मार्फत डेटा वा इन्टरनेट प्रयोग गर्न सक्नुहुने छैन। Wi-Fi मार्फत मात्र इन्टरनेट उपलब्ध हुने छ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"तपाईंको सेवा प्रदायक"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"कुनै अनुप्रयोगको कारणले अनुमतिसम्बन्धी अनुरोध बुझ्न गाह्रो भइरहेकोले सेटिङहरूले तपाईंको प्रतिक्रिया प्रमाणित गर्न सक्दैनन्।"</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"कुनै एपको कारणले अनुमतिसम्बन्धी अनुरोध बुझ्न गाह्रो भइरहेकोले सेटिङहरूले तपाईंको प्रतिक्रिया प्रमाणित गर्न सक्दैनन्।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> लाई <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन अनुमति दिने हो?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- यसले <xliff:g id="APP">%1$s</xliff:g> बाट जानकारी पढ्न सक्छ"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- यसले <xliff:g id="APP">%1$s</xliff:g> भित्र कारबाही गर्न सक्छ"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string>
<string name="restart_button_description" msgid="6916116576177456480">"यो एप पुनः सुरु गर्न ट्याप गर्नुहोस् र फुल स्क्रिन मोडमा जानुहोस्।"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> का बबलसम्बन्धी सेटिङहरू"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ओभरफ्लो देखाउनुहोस्"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"स्ट्याकमा फेरि थप्नुहोस्"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"व्यवस्थापन गर्नुहोस्"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> को <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> का <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> र थप <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"पावर मेनुबाट प्रयोग गर्न चाहेका नियन्त्रण सुविधाहरू छान्नुहोस्"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"नियन्त्रणहरूको क्रम मिलाउन तिनलाई थिचेर ड्र्याग गर्नुहोस्"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"सबै नियन्त्रणहरू हटाइए"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"परिवर्तनहरू सुरक्षित गरिएका छैनन्"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"सबै नियन्त्रणहरूको सूची लोड गर्न सकिएन।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"यन्त्र नियन्त्रण गर्ने विजेटहरूको सूचीमा थप्नुहोस्"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"मन पर्ने कुराहरूमा थप्नुहोस्"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ले यो नियन्त्रण तपाईंका मन पर्ने कुराहरूमा थप्न सुझाव सिफारिस गरेको छ।"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"थप्नुहोस्"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ले सिफारिस गरेको"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"नियन्त्रण सुविधाहरू अद्यावधिक गरिए"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN मा अक्षर वा चिन्हहरू समाविष्ट हुन्छन्"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> पुष्टि गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 2d51011..196357c 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -79,6 +79,7 @@
<color name="global_screenshot_button_icon">@color/GM2_blue_300</color>
<color name="global_screenshot_dismiss_background">@color/GM2_grey_800</color>
<color name="global_screenshot_dismiss_foreground">#FFFFFF</color>
+ <color name="global_screenshot_background_protection_start">#80000000</color> <!-- 50% black -->
<!-- Biometric dialog colors -->
diff --git a/packages/SystemUI/res/values-night/dimens.xml b/packages/SystemUI/res/values-night/dimens.xml
index 4814839..23e3231 100644
--- a/packages/SystemUI/res/values-night/dimens.xml
+++ b/packages/SystemUI/res/values-night/dimens.xml
@@ -18,4 +18,8 @@
<resources>
<!-- The height of the divider between the individual notifications. -->
<dimen name="notification_divider_height">1dp</dimen>
+
+ <!-- Height of the background gradient behind the screenshot UI (taller in dark mode) -->
+ <dimen name="screenshot_bg_protection_height">375dp</dimen>
+
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 25965136..419fa3e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Screenshot sluiten"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Voorbeeld van screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Opname starten?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Tijdens de opname kan het Android-systeem gevoelige informatie opnemen die zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Dit omvat wachtwoorden, betalingsgegevens, foto\'s, berichten en audio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Beheren"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Geschiedenis"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkomend"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Stille meldingen"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Meldingen met waarschuwing"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekken"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tik om deze app opnieuw te starten en te openen op het volledige scherm."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-bubbels"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overloop"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Weer toevoegen aan stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Beheren"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kan lijst met alle bedieningselementen niet laden."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Toevoegen aan apparaatbediening"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Toevoegen aan favorieten"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> heeft voorgesteld dit bedieningselement toe te voegen aan je favorieten."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Toevoegen"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Voorgesteld door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Bedieningselementen geüpdated"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pincode bevat letters of symbolen"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> verifiëren"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index f5e7f12..ef753b8 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ସ୍କ୍ରିନସଟ୍ ଖାରଜ କରନ୍ତୁ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ସ୍କ୍ରିନସଟର ପ୍ରିଭ୍ୟୁ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ସ୍କ୍ରିନ୍ ରେକର୍ଡର୍"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରିନ୍ ରେକର୍ଡ୍ ସେସନ୍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବେ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ରେକର୍ଡିଂ ସମୟରେ, Android ସିଷ୍ଟମ୍ ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା ବା ଆପଣଙ୍କ ଡିଭାଇସରେ ଚାଲୁଥିବା ଯେ କୌଣସି ସମ୍ବେଦନଶୀଳ ସୂଚନାକୁ କ୍ୟାପଚର୍ କରିପାରିବ। ଏଥିରେ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ସୂଚନା, ଫଟୋ, ମେସେଜ ଏବଂ ଅଡିଓ ଅନ୍ତର୍ଭୁକ୍ତ।"</string>
@@ -210,7 +211,7 @@
<string name="accessibility_three_bars" msgid="819417766606501295">"ତିନୋଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_signal_full" msgid="5920148525598637311">"ସିଗ୍ନାଲ୍ ଫୁଲ୍ ଅଛି।"</string>
<string name="accessibility_desc_on" msgid="2899626845061427845">"ଚାଲୁ।"</string>
- <string name="accessibility_desc_off" msgid="8055389500285421408">"ଅଫ୍।"</string>
+ <string name="accessibility_desc_off" msgid="8055389500285421408">"ବନ୍ଦ।"</string>
<string name="accessibility_desc_connected" msgid="3082590384032624233">"ସଂଯୁକ୍ତ।"</string>
<string name="accessibility_desc_connecting" msgid="8011433412112903614">"ସଂଯୋଗ କରୁଛି।"</string>
<string name="data_connection_gprs" msgid="2752584037409568435">"GPRS"</string>
@@ -231,7 +232,7 @@
<string name="accessibility_cell_data_on" msgid="691666434519443162">"ମୋବାଇଲ୍ ଡାଟା ଅନ୍"</string>
<string name="cell_data_off_content_description" msgid="9165555931499878044">"ମୋବାଇଲ୍ ଡାଟା ବନ୍ଦ ଅଛି"</string>
<string name="not_default_data_content_description" msgid="6757881730711522517">"ବ୍ୟବହୃତ ଡାଟା ପାଇଁ ସେଟ୍ ହୋଇନାହିଁ"</string>
- <string name="cell_data_off" msgid="4886198950247099526">"ଅଫ୍ ଅଛି"</string>
+ <string name="cell_data_off" msgid="4886198950247099526">"ବନ୍ଦ"</string>
<string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"ବ୍ଲୁଟୁଥ ଟିଥରିଂ।"</string>
<string name="accessibility_airplane_mode" msgid="1899529214045998505">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍।"</string>
<string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN ଅନ୍।"</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା।"</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ଦ୍ରୁତ ସେଟିଂସ୍।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string>
@@ -499,7 +499,7 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"ୟୁଜରଙ୍କୁ ବାହାର କରିବେ?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"ଏହି ୟୁଜରଙ୍କ ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"ବାହାର କରନ୍ତୁ"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ ଅଛି"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"ବ୍ୟାଟେରୀ ସେଭର୍ ଚାଲୁ ଅଛି"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"କାର୍ଯ୍ୟ ସମ୍ପାଦନ ଓ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଡାଟା କମ୍ କରନ୍ତୁ"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅଫ୍ କରନ୍ତୁ"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ରେ ସମସ୍ତ ସୂଚନାକୁ ଆକ୍ସେସ୍ ରହିବ ଯାହା ଆପଣଙ୍କର ସ୍କ୍ରିନ୍ରେ ଦେଖାଯିବ ବା ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ବେଳେ ଆପଣଙ୍କର ଡିଭାଇସ୍ ଠାରୁ ଚାଲିବ। ପାସ୍ୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ୍ ଏବଂ ଆପଣ ଚଲାଉଥିବା ଅଡିଓ ପରି ସୂଚନା ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ଇତିହାସ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ଇନକମିଂ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ନୀରବ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"ଆଲର୍ଟ କରିବା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
@@ -581,7 +582,7 @@
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ନାହିଁ, ଥାଉ"</string>
<string name="hidden_notifications_setup" msgid="2064795578526982467">"ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
- <string name="volume_zen_end_now" msgid="5901885672973736563">"ବର୍ତ୍ତମାନ ଅଫ୍ କରନ୍ତୁ"</string>
+ <string name="volume_zen_end_now" msgid="5901885672973736563">"ବର୍ତ୍ତମାନ ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ସାଉଣ୍ଡ ସେଟିଂସ୍"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"ବଢ଼ାନ୍ତୁ"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"ଛୋଟ କରନ୍ତୁ"</string>
@@ -683,7 +684,7 @@
<string name="do_not_silence_block" msgid="4361847809775811849">"ନିରବ କିମ୍ବା ବ୍ଲକ୍ କରନ୍ତୁ ନାହିଁ"</string>
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"ପାୱାର୍ ବିଜ୍ଞପ୍ତି କଣ୍ଟ୍ରୋଲ୍"</string>
<string name="tuner_full_importance_settings_on" msgid="917981436602311547">"ଚାଲୁ"</string>
- <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"ଅଫ୍"</string>
+ <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"ବନ୍ଦ"</string>
<string name="power_notification_controls_description" msgid="1334963837572708952">"ପାୱାର୍ ବିଜ୍ଞପ୍ତି କଣ୍ଟ୍ରୋଲ୍ରେ, ଆପଣ ଏକ ଆପ୍ ବିଜ୍ଞପ୍ତି ପାଇଁ 0 ରୁ 5 ଗୁରୁତ୍ୱ ସ୍ତର ସେଟ୍ କରିହେବେ। \n\n"<b>"ସ୍ତର 5"</b>" \n- ବିଜ୍ଞପ୍ତି ତାଲିକାର ଶୀର୍ଷରେ ଦେଖାନ୍ତୁ \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ \n- ସର୍ବଦା ପିକ୍ କରନ୍ତୁ \n\n"<b>"ସ୍ତର 4"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- ସର୍ବଦା ପିକ୍ କରନ୍ତୁ \n\n"<b>"ସ୍ତର 3"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n\n"<b>"ସ୍ତର 2"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n- କଦାପି ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ ନାହିଁ \n\n"<b>"ସ୍ତର 1"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n- କଦାପି ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ ନାହିଁ \n- ଲକ୍ ସ୍କ୍ରୀନ୍ ଓ ଷ୍ଟାଟସ୍ ବାର୍ରୁ ଲୁଚାନ୍ତୁ \n- ବିଜ୍ଞପ୍ତି ତାଲିକାର ନିମ୍ନରେ ଦେଖାନ୍ତୁ \n\n"<b>"ସ୍ତର 0"</b>" \n- ଆପରୁ ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବ୍ଲକ୍ କରନ୍ତୁ"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"ବିଜ୍ଞପ୍ତି"</string>
<string name="notification_channel_disabled" msgid="928065923928416337">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଆପଣ ଆଉ ଦେଖିବାକୁ ପାଇବେନାହିଁ।"</string>
@@ -833,7 +834,7 @@
<item msgid="2681220472659720036">"କ୍ଲିପ୍ବୋର୍ଡ"</item>
<item msgid="4795049793625565683">"କୀ\'କୋଡ୍"</item>
<item msgid="80697951177515644">"ଘୁରାଇବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ, କୀ’ବୋର୍ଡର ଭାଷା ପରିବର୍ତ୍ତନ ସୁବିଧା"</item>
- <item msgid="7626977989589303588">"କିଛିନୁହେଁ"</item>
+ <item msgid="7626977989589303588">"କିଛି ନାହିଁ"</item>
</string-array>
<string-array name="nav_bar_layouts">
<item msgid="9156773083127904112">"ସାମାନ୍ୟ"</item>
@@ -929,7 +930,7 @@
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ଡାହାଣ ଶର୍ଟକଟ୍"</string>
<string name="lockscreen_unlock_left" msgid="1417801334370269374">"ବାମ ଶର୍ଟକଟ୍ ମଧ୍ୟ ଅନଲକ୍ କରେ"</string>
<string name="lockscreen_unlock_right" msgid="4658008735541075346">"ଡାହାଣ ଶର୍ଟକଟ୍ ମଧ୍ୟ ଅନଲକ୍ କରେ"</string>
- <string name="lockscreen_none" msgid="4710862479308909198">"କିଛିନୁହେଁ"</string>
+ <string name="lockscreen_none" msgid="4710862479308909198">"କିଛି ନାହିଁ"</string>
<string name="tuner_launch_app" msgid="3906265365971743305">"<xliff:g id="APP">%1$s</xliff:g> ଲଞ୍ଚ କରନ୍ତୁ"</string>
<string name="tuner_other_apps" msgid="7767462881742291204">"ଅନ୍ୟ ଆପ୍ସ"</string>
<string name="tuner_circle" msgid="5270591778160525693">"ବୃତ୍ତ"</string>
@@ -974,7 +975,7 @@
<string name="slice_permission_text_2" msgid="6758906940360746983">"- ଏହା <xliff:g id="APP">%1$s</xliff:g> ଭିତରେ କାମ କରିପାରିବ"</string>
<string name="slice_permission_checkbox" msgid="4242888137592298523">"ଯେକୌଣସି ଆପ୍ରେ ସ୍ଲାଇସ୍କୁ ଦେଖାଇବା ପାଇଁ <xliff:g id="APP">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
- <string name="slice_permission_deny" msgid="6870256451658176895">"ଅସ୍ଵୀକାର କରନ୍ତୁ"</string>
+ <string name="slice_permission_deny" msgid="6870256451658176895">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ ହେବାର ସମୟ ସେଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"ବ୍ୟାଟେରୀ ସରିବାକୁ ଥିବା ସମୟରେ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ନାହିଁ, ଥାଉ"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ଏହି ଆପ୍କୁ ରିଷ୍ଟାର୍ଟ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ ଏବଂ ଫୁଲ୍ସ୍କ୍ରିନ୍କୁ ଯାଆନ୍ତୁ।"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବବଲ୍ଗୁଡ଼ିକ ପାଇଁ ସେଟିଂସ୍"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ଓଭରଫ୍ଲୋ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ଷ୍ଟାକରେ ପୁଣି ଯୋଗ କରନ୍ତୁ"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ଏବଂ ଅଧିକ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>ଟିରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1010,7 +1013,7 @@
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ବାର୍ତ୍ତାଳାପ ବିଭାଗର ଶୀର୍ଷରେ ଦେଖାନ୍ତୁ"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ଲକ୍ ସ୍କ୍ରିନରେ ପ୍ରୋଫାଇଲ୍ ଛବି ଦେଖାନ୍ତୁ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ଆପଗୁଡ଼ିକ ଉପରେ ଫ୍ଲୋଟିଂ ବବଲ୍ ପରି ଦେଖାଯିବ"</string>
- <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ମୋଡରେ ବାଧା ଉପୁଯାଇପାରିବ"</string>
+ <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ମୋଡରେ ବାଧା"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ବୁଝିଗଲି"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ଓଭର୍ଲେ ୱିଣ୍ଡୋ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ପାୱାର ମେନୁରୁ ଆକ୍ସେସ୍ କରିବାକୁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ବାଛନ୍ତୁ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ପୁଣି ସଜାଇବାକୁ ସେଗୁଡ଼ିକୁ ଧରି ଟାଣନ୍ତୁ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ସମସ୍ତ ନିୟନ୍ତ୍ରଣ କାଢ଼ି ଦିଆଯାଇଛି"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ପରିବର୍ତ୍ତନଗୁଡ଼ିକ ସେଭ୍ କରାଯାଇନାହିଁ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ସବୁ ନିୟନ୍ତ୍ରଣର ତାଲିକା ଲୋଡ୍ କରିପାରିଲା ନାହିଁ।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ଅନ୍ୟ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକରେ ଯୋଗ କରନ୍ତୁ"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ପସନ୍ଦଗୁଡ଼ିକରେ ଯୋଗ କରନ୍ତୁ"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"ଏହି ନିୟନ୍ତ୍ରଣକୁ ଆପଣଙ୍କ ପସନ୍ଦଗୁଡ଼ିକରେ ଯୋଗ କରିବାକୁ <xliff:g id="APP">%s</xliff:g> ପ୍ରସ୍ତାବ ଦେଇଛି।"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରସ୍ତାବିତ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଅପଡେଟ୍ କରାଯାଇଛି"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ସଙ୍କେତଗୁଡ଼ିକ ଥାଏ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ଯାଞ୍ଚ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 37cf38c..b9db02a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ਕੀ ਰਿਕਾਰਡਿੰਗ ਸ਼ੁਰੂ ਕਰਨੀ ਹੈ?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ਰਿਕਾਰਡਿੰਗ ਕਰਨ ਵੇਲੇ, Android ਸਿਸਟਮ ਕੋਈ ਵੀ ਅਜਿਹੀ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਕੈਪਚਰ ਕਰ ਸਕਦਾ ਹੈ ਜੋ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੈ ਜਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡ, ਭੁਗਤਾਨ ਵੇਰਵੇ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹੇ ਅਤੇ ਆਡੀਓ ਸ਼ਾਮਲ ਹਨ।"</string>
@@ -356,7 +357,7 @@
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"ਚਮਕ"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁੰਮਾਓ"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"<xliff:g id="ID_1">%s</xliff:g> ਮੋਡ"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"ਰੋਟੇਸ਼ਨ ਲਾਕ ਕੀਤੀ"</string>
@@ -367,7 +368,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਬੰਦ"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ਮੀਡੀਆ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
- <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ਕੇਵਲ ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ"</string>
+ <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ਸਿਰਫ਼ ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ"</string>
<string name="quick_settings_settings_label" msgid="2214639529565474534">"ਸੈਟਿੰਗਾਂ"</string>
<string name="quick_settings_time_label" msgid="3352680970557509303">"ਸਮਾਂ"</string>
<string name="quick_settings_user_label" msgid="1253515509432672496">"ਮੈਂ"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ਇਨਕਮਿੰਗ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ਸ਼ਾਂਤ ਸੂਚਨਾਵਾਂ"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"ਸੁਚੇਤ ਕਰਨ ਵਾਲੀਆਂ ਸੂਚਨਾਵਾਂ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string>
@@ -850,7 +852,7 @@
<string name="right_keycode" msgid="2480715509844798438">"ਸੱਜਾ ਕੀ-ਕੋਡ"</string>
<string name="left_icon" msgid="5036278531966897006">"ਖੱਬਾ ਪ੍ਰਤੀਕ"</string>
<string name="right_icon" msgid="1103955040645237425">"ਸੱਜਾ ਪ੍ਰਤੀਕ"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"ਟਾਇਲਾਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਰੱਖੋ ਅਤੇ ਘਸੀਟੋ"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"ਟਾਇਲਾਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ਟਾਇਲਾਂ ਨੂੰ ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ਤੁਹਾਨੂੰ ਘੱਟੋ-ਘੱਟ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ਟਾਇਲਾਂ ਦੀ ਲੋੜ ਪਵੇਗੀ"</string>
@@ -960,7 +962,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ਐਪ (<xliff:g id="ID_1">%s</xliff:g>) ਵੱਲੋਂ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ਇੱਕ ਸਵੈਚਲਿਤ ਨਿਯਮ ਜਾਂ ਐਪ ਵੱਲੋਂ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> ਤੱਕ"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"ਰੱਖੋ"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"ਬਦਲੋ"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀਆਂ ਐਪਾਂ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ਬੈਟਰੀ ਅਤੇ ਡਾਟਾ ਵਰਤੋਂ ਸਬੰਧੀ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਓ।"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਬਬਲ ਲਈ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ਓਵਰਫ਼ਲੋ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ਸਟੈਕ ਵਿੱਚ ਵਾਪਸ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਅਤੇ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ਹੋਰਾਂ ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ਸਾਰੇ ਕੰਟਰੋਲਾਂ ਦੀ ਸੂਚੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ਨੇ ਇਸ ਕੰਟਰੋਲ ਨੂੰ ਤੁਹਾਡੇ ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਸੁਝਾਅ ਦਿੱਤਾ ਹੈ।"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ਵੱਲੋਂ ਸੁਝਾਇਆ ਗਿਆ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ਕੰਟਰੋਲ ਅੱਪਡੇਟ ਕੀਤੇ ਗਏ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਹਨ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 087ab50..19d9a6e 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zamknij zrzut ekranu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Podgląd zrzutu ekranu"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Rozpocząć nagrywanie?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Podczas nagrywania system Android może rejestrować wszelkie informacje poufne wyświetlane na ekranie lub odtwarzane na urządzeniu. Dotyczy to m.in. haseł, szczegółów płatności, zdjęć, wiadomości i odtwarzanych dźwięków."</string>
@@ -417,7 +418,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Wykorzyst.: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limit <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Profil do pracy"</string>
+ <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Profil służbowy"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Podświetlenie nocne"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Włącz o zachodzie"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do wschodu słońca"</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Zarządzaj"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Przychodzące"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Ciche powiadomienia"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Alerty"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez tytułu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Kliknij, by uruchomić tę aplikację ponownie i przejść w tryb pełnoekranowy."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Ustawienia dymków aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Przepełnienie"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj ponownie do stosu"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Zarządzaj"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g> i jeszcze <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nie udało się wczytać listy elementów sterujących."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodaj do sterowania urządzeniami"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodaj do ulubionych"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacja <xliff:g id="APP">%s</xliff:g> zaproponowała dodanie tego elementu sterującego do ulubionych."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugestia: <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Zaktualizowano elementy sterujące"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kod PIN zawiera litery lub symbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Sprawdź urządzenie <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index c22a277..d63d623 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -33,7 +33,7 @@
<string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Usar o carregador que acompanha o dispositivo"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Configurações"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar Economia de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar \"Economia de bateria\"?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre a Economia de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Economia de bateria"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dispensar captura de tela"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Iniciar gravação?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Durante a gravação, o sistema Android pode capturar informações confidenciais visíveis na tela ou tocadas no dispositivo. Isso inclui senhas, informações de pagamento, fotos, mensagens e áudio."</string>
@@ -435,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslize para cima para alternar entre os apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para alternar rapidamente entre os apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregado"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Carregando"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Não está carregando"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Recebidas"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificações silenciosas"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificações com alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -681,7 +683,7 @@
<string name="do_not_silence" msgid="4982217934250511227">"Não silenciar"</string>
<string name="do_not_silence_block" msgid="4361847809775811849">"Não silenciar ou bloquear"</string>
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"Controles de ativação/desativação de notificações"</string>
- <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Ativado"</string>
+ <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Ativada"</string>
<string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Desativado"</string>
<string name="power_notification_controls_description" msgid="1334963837572708952">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"Notificações"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar o app e usar tela cheia."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configurações de balões do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu flutuante"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Devolver à pilha"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gerenciar"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> mais <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Adicionar aos favoritos"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sugeriu a adição desse controle aos seus favoritos."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT-ldrtl/strings.xml b/packages/SystemUI/res/values-pt-rPT-ldrtl/strings.xml
index 58923fb..4af54b5 100644
--- a/packages/SystemUI/res/values-pt-rPT-ldrtl/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT-ldrtl/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"Arrastar para a esquerda para mudar rapidamente de aplicação"</string>
+ <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"Arrastar para a esquerda para mudar rapidamente de app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index cea04db..2b34ac3 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignorar captura de ecrã"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pré-visualização da captura de ecrã"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de ecrã"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"A processar a gravação de ecrã"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação persistente de uma sessão de gravação de ecrã"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Pretende iniciar a gravação?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Enquanto estiver a gravar, o sistema Android pode capturar quaisquer informações confidenciais que estejam visíveis no ecrã ou que sejam reproduzidas no dispositivo. Isto inclui palavras-passe, informações de pagamento, fotos, mensagens e áudio."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gerir"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"A receber"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificações silenciosas"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificações de alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -944,7 +946,7 @@
<string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugestões"</string>
- <string name="instant_apps" msgid="8337185853050247304">"Aplicações instantâneas"</string>
+ <string name="instant_apps" msgid="8337185853050247304">"Apps instantâneas"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
<string name="instant_apps_message" msgid="6112428971833011754">"A app é aberta sem ser instalada."</string>
<string name="instant_apps_message_with_help" msgid="1816952263531203932">"A app é aberta sem ser instalada. Toque para saber mais."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar esta app e ficar em ecrã inteiro."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Definições dos balões da app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu adicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Adicionar novamente à pilha"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gerir"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do <xliff:g id="APP_NAME">%2$s</xliff:g> e mais<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>."</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista dos controlos."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adicione aos controlos de dispositivos"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Adicionar aos favoritos"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"A app <xliff:g id="APP">%s</xliff:g> sugeriu este controlo para adicionar aos seus favoritos."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlos atualizados"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Valide <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c22a277..d63d623 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -33,7 +33,7 @@
<string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Usar o carregador que acompanha o dispositivo"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Configurações"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar Economia de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar \"Economia de bateria\"?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre a Economia de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Economia de bateria"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dispensar captura de tela"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Iniciar gravação?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Durante a gravação, o sistema Android pode capturar informações confidenciais visíveis na tela ou tocadas no dispositivo. Isso inclui senhas, informações de pagamento, fotos, mensagens e áudio."</string>
@@ -435,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslize para cima para alternar entre os apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para alternar rapidamente entre os apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregado"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Carregando"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Não está carregando"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Recebidas"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificações silenciosas"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificações com alerta"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -681,7 +683,7 @@
<string name="do_not_silence" msgid="4982217934250511227">"Não silenciar"</string>
<string name="do_not_silence_block" msgid="4361847809775811849">"Não silenciar ou bloquear"</string>
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"Controles de ativação/desativação de notificações"</string>
- <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Ativado"</string>
+ <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Ativada"</string>
<string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Desativado"</string>
<string name="power_notification_controls_description" msgid="1334963837572708952">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"Notificações"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar o app e usar tela cheia."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configurações de balões do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu flutuante"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Devolver à pilha"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gerenciar"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> mais <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Adicionar aos favoritos"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sugeriu a adição desse controle aos seus favoritos."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 519eddda..ce8b05f 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Închideți captura de ecran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Previzualizare a capturii de ecran"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Începeți înregistrarea?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"În timpul înregistrării, sistemul Android poate captura informațiile sensibile vizibile pe ecran sau redate pe dispozitiv. Aici sunt incluse parole, informații de plată, fotografii, mesaje și conținut audio."</string>
@@ -512,6 +513,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Ștergeți toate notificările"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gestionați"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Istoric"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Primite"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificări silențioase"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificări de alertare"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversații"</string>
@@ -992,6 +994,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Fără titlu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Atingeți ca să reporniți aplicația și să treceți în modul ecran complet."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Setări pentru baloanele <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Suplimentar"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Adăugați înapoi în stivă"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gestionați"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g> și încă <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1037,8 +1041,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista cu toate comenzile nu a putut fi încărcată."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adăugați la comenzile dispozitivelor"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Adăugați la preferate"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> a sugerat adăugarea acestei comenzi la preferate."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Adăugați"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugerat de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"S-au actualizat comenzile"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Codul PIN conține litere sau simboluri"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificați <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ad7f175..38d8874 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -88,7 +88,8 @@
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string>
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Закрыть скриншот"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Предварительный просмотр скриншота"</string>
- <string name="screenrecord_name" msgid="2596401223859996572">"Создание скриншотов"</string>
+ <string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Начать запись?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Во время записи система Android может получить доступ к конфиденциальной информации, которая видна на экране или воспроизводится на устройстве, в том числе к паролям, сведениям о платежах, фотографиям, сообщениям и аудиозаписям."</string>
@@ -99,7 +100,7 @@
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Звук с устройства и микрофон"</string>
<string name="screenrecord_start" msgid="330991441575775004">"Начать"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Идет запись видео с экрана."</string>
- <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Идет запись видео с экрана и звука."</string>
+ <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Идет запись видео с экрана и звука"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"Показывать прикосновения к экрану"</string>
<string name="screenrecord_stop_text" msgid="6549288689506057686">"Нажмите, чтобы остановить"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"Остановить"</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Очистить все"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Настроить"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Входящие"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Беззвучные уведомления"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Оповещения"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Нажмите, чтобы перезапустить приложение и перейти в полноэкранный режим."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Настройки всплывающих чатов от приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Дополнительное меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Добавить обратно в стек"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Настроить"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" и ещё <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не удалось загрузить список элементов управления."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Добавьте виджеты управления устройствами"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Добавить в избранное"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" предлагает добавить этот элемент управления в избранное."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавить"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Предложено приложением \"<xliff:g id="APP">%s</xliff:g>\""</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы управления обновлены."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код содержит буквы или символы"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Подтвердите устройство \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 2011bf0..abe2dc2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"තිර රුව ඉවත ලන්න"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"තිර රූ පෙර දසුන"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"තිර රෙකෝඩරය"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"පටිගත කිරීම ආරම්භ කරන්නද?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"පටිගත කරන අතරතුර, Android පද්ධතියට ඔබේ තිරයේ පෙනෙන හෝ ඔබේ උපාංගයේ වාදනය කරන ඕනෑම සංවේදී තොරතුරක් ග්රහණය කර ගැනීමට හැකිය. මෙයට මුරපද, ගෙවීම් තොරතුරු, ඡායාරූප, පණිවිඩ සහ ඕඩියෝ ඇතුළත් වේ."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"සියල්ල හිස් කරන්න"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"කළමනාකරණය කරන්න"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ඉතිහාසය"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"එන"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"නිහඬ දැනුම්දීම්"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"ඇඟවීමේ දැනුම් දීම්"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"සංවාද"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"මාතෘකාවක් නැත"</string>
<string name="restart_button_description" msgid="6916116576177456480">"මෙම යෙදුම යළි ඇරඹීමට සහ පූර්ණ තිරයට යාමට තට්ටු කරන්න"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> බුබුළු සඳහා සැකසීම්"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"පිටාර යාම"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"අට්ටිය වෙත ආපසු එක් කරන්න"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"කළමනා කරන්න"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> වෙතින් <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> වෙතින් <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සහ තවත් <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ක්"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"සියලු පාලනවල ලැයිස්තුව පූරණය කළ නොහැකි විය."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"උපාංග පාලන වෙත එක් කරන්න"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ප්රියතම වෙත එක් කරන්න"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ඔබේ ප්රියතම වෙත එක් කිරීමට මෙම පාලනය යෝජනා කරන ලදී."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"එක් කරන්න"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"යෝජනා කළේ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"පාලන යාවත්කාලීනයි"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN හි අකුරු හෝ සංකේත අඩංගු වේ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> සත්යාපනය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 6fd6d87..f9535fa 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zavrieť snímku obrazovky"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ukážka snímky obrazovky"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Chcete spustiť nahrávanie?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Počas nahrávania zaznamená systém Android všetky citlivé údaje, ktoré sa zobrazia na obrazovke alebo prehrajú v zariadení. Zahrnuje to heslá, platobné údaje, fotky, správy a zvuky."</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Spravovať"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"História"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Prichádzajúce"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Tiché upozornenia"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Varovné upozornenia"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzácie"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Klepnutím reštartujete túto aplikáciu a prejdete do režimu celej obrazovky."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Nastavenia bublín aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Rozšírená ponuka"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Pridať späť do zásobníka"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Spravovať"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g> a ďalšie (<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
@@ -1024,9 +1028,9 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Okno prekrytia priblíženia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládacie prvky okna priblíženia"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadenia"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte ovládacie prvky pre svoje pripojené zariadenia"</string>
- <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadenia"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadení"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Pridržaním vypínača získate prístup k ovládacím prvkom"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Výberom aplikácie pridajte ovládacie prvky"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1042,9 +1046,9 @@
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmeny neboli uložené"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Zoznam všetkých ovl. prvkov sa nepodarilo načítať."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"Pridanie do ovládania zariadenia"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Pridať do obľúbených"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikácia <xliff:g id="APP">%s</xliff:g> vám odporučila pridať tento ovládací prvok do obľúbených."</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"Pridanie do ovládania zariadení"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridať"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Navrhuje <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládanie bolo aktualizované"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmená alebo symboly"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Overiť <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index aade5c2..cbfee80 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Opusti posnetek zaslona"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Predogled posnetka zaslona"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snemalnik zaslona"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Želite začeti snemati?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Med snemanjem lahko sistem Android zajame morebitne občutljive podatke, ki so prikazani na zaslonu ali se predvajajo v napravi. To vključuje gesla, podatke za plačilo, fotografije, sporočila in zvok."</string>
@@ -390,7 +391,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Povezava Wi-Fi ni vzpostavljena"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svetlost"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"SAMODEJNO"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Obrni barve"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzija barv"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Način popravljanja barv"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Več nastavitev"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši vse"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Upravljanje"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Zgodovina"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dohodno"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Tiha obvestila"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Obvestila z opozorilom"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Pogovori"</string>
@@ -675,7 +677,7 @@
<string name="remove_from_settings_prompt" msgid="551565437265615426">"Ali želite odstraniti Uglaševalnik uporabniškega vmesnika sistema iz nastavitev in prenehati uporabljati vse njegove funkcije?"</string>
<string name="activity_not_found" msgid="8711661533828200293">"Aplikacija ni nameščena v napravi"</string>
<string name="clock_seconds" msgid="8709189470828542071">"Prikaz sekund pri uri"</string>
- <string name="clock_seconds_desc" msgid="2415312788902144817">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
+ <string name="clock_seconds_desc" msgid="2415312788902144817">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri baterijskem napajanju."</string>
<string name="qs_rearrange" msgid="484816665478662911">"Preuredi hitre nastavitve"</string>
<string name="show_brightness" msgid="6700267491672470007">"Prikaz svetlosti v hitrih nastavitvah"</string>
<string name="experimental" msgid="3549865454812314826">"Poskusno"</string>
@@ -975,7 +977,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacije, ki se izvajajo v ozadju"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Dotaknite se za prikaz podrobnosti porabe baterije in prenosa podatkov"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite izklopiti prenos podatkov v mobilnih omrežjih?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prek operaterja <xliff:g id="CARRIER">%s</xliff:g> ne boste imeli dostopa do podatkovne povezave ali interneta. Internet bo na voljo samo prek povezave Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prek operaterja »<xliff:g id="CARRIER">%s</xliff:g>« ne boste imeli dostopa do podatkovne povezave ali interneta. Internet bo na voljo samo prek povezave Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"svojega operaterja"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Ker aplikacija zakriva zahtevo za dovoljenje, z nastavitvami ni mogoče preveriti vašega odziva."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Želite dovoliti, da aplikacija <xliff:g id="APP_0">%1$s</xliff:g> prikaže izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
@@ -987,8 +989,8 @@
<string name="auto_saver_title" msgid="6873691178754086596">"Dotaknite se za načrtovanje varčevanja z energijo baterije"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"Vklop, če je verjetno, da se bo baterija izpraznila"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string>
- <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Urnik varčevanja z energijo akumulatorja je vklopljen"</string>
- <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Varčevanje z energijo akumulatorja se bo samodejno vklopilo, ko bo energija akumulatorja pod <xliff:g id="PERCENTAGE">%d</xliff:g> %%."</string>
+ <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Urnik varčevanja z energijo baterije je vklopljen"</string>
+ <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Varčevanje z energijo baterije se bo samodejno vklopilo, ko bo energija baterije pod <xliff:g id="PERCENTAGE">%d</xliff:g> %%."</string>
<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>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Brez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dotaknite se za vnovični zagon te aplikacije in preklop v celozaslonski način."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Nastavitve za oblačke aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Prelivanje"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj nazaj v sklad"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljanje"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> in toliko drugih: <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Seznama vseh kontrolnikov ni bilo mogoče naložiti."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodajanje med kontrolnike naprave"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodaj med priljubljene"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacija <xliff:g id="APP">%s</xliff:g> je predlagala, da ta kontrolnik dodate med priljubljene."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Predlagala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrolniki so posodobljeni"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Koda PIN vsebuje črke ali simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Preverjanje naprave <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 0d85f21..ea66526 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Hiq pamjen e ekranit"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pamja paraprake e imazhit"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Regjistruesi i ekranit"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Të nis regjistrimi?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Gjatë regjistrimit, sistemi Android mund të regjistrojë çdo informacion delikat që është i dukshëm në ekranin tënd ose që luhet në pajisje. Kjo përfshin fjalëkalimet, informacionin e pagesave, fotografitë, mesazhet dhe audion."</string>
@@ -435,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Rrëshqit shpejt lart për të ndërruar aplikacionet"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zvarrit djathtas për të ndërruar aplikacionet me shpejtësi"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kalo te përmbledhja"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"I ngarkuar"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"I karikuar"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Po karikohet"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> deri sa të mbushet"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Nuk po karikohet"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Pastroji të gjitha"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Menaxho"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historiku"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Hyrëse"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Njoftimet në heshtje"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Njoftimet sinjalizuese"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Pa titull"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Trokit për ta rinisur këtë aplikacion dhe për të kaluar në ekranin e plotë."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Cilësimet për flluskat e <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Tejkalo"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Shto përsëri te stiva"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Menaxho"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> nga <xliff:g id="APP_NAME">%2$s</xliff:g> dhe <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> të tjera"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista e të gjitha kontrolleve nuk mund të ngarkohej."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Shto te kontrollet e pajisjes"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Shto te të preferuarat"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sugjeroi këtë kontroll për ta shtuar te të preferuarat e tua."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Shto"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Sugjeruar nga <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollet u përditësuan"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kodi PIN përmban shkronja ose simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifiko <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 7fd0371..17a01b2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Одбаците снимак екрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед снимка екрана"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач екрана"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Желите да започнете снимање?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Током снимања Android систем може да сними осетљиве информације које су видљиве на екрану или које се пуштају на уређају. То обухвата лозинке, информације о плаћању, слике, поруке и звук."</string>
@@ -396,7 +397,7 @@
<string name="quick_settings_connected" msgid="3873605509184830379">"Повезан"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Повезано, ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"Повезује се..."</string>
- <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Повезивање"</string>
+ <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Привезивање"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Хотспот"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Укључује се..."</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Уштеда података је укључена"</string>
@@ -512,6 +513,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Управљајте"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Долазно"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Нечујна обавештења"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Обавештења која привлаче пажњу"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Конверзације"</string>
@@ -992,6 +994,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслова"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Додирните да бисте рестартовали апликацију и прешли у режим целог екрана."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Подешавања за <xliff:g id="APP_NAME">%1$s</xliff:g> облачиће"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Преклапање"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Додај поново у групу"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Управљајте"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из апликације <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из апликације <xliff:g id="APP_NAME">%2$s</xliff:g> и још <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1011,10 +1015,10 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигација система је ажурирана. Да бисте унели измене, идите у Подешавања."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Приказују се у врху одељка за конверзације"</string>
- <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Приказују слику профила на закључаном екрану"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Приказује се у врху одељка за конверзације"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Приказује слику профила на закључаном екрану"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Приказују се плутајући облачићи преко апликација"</string>
- <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ометају подешавање Не узнемиравај"</string>
+ <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Омета подешавање Не узнемиравај"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Важи"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Преклопни прозор за увећање"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string>
@@ -1037,8 +1041,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Учитавање листе свих контрола није успело."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Додајте у контроле уређаја"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Додајте у омиљене"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> предлаже да додате ову контролу у омиљене."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Предлаже <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Контроле су ажуриране"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN садржи слова или симболе"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Верификујте: <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f915f6c..7ff1f84 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Stäng skärmdump"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Förhandsgranskning av skärmdump"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skärminspelare"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Avisering om att skärminspelning pågår"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Vill du starta inspelningen?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"När du spelar in kan Android-systemet registrera alla känsliga uppgifter som visas på skärmen eller spelas upp på enheten. Detta omfattar lösenord, betalningsuppgifter, foton, meddelanden och ljud."</string>
@@ -398,7 +399,7 @@
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"Internetdelning"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Surfzon"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Aktiverar …"</string>
- <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Databesparing är på"</string>
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Databesparing på"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
<item quantity="other">%d enheter</item>
<item quantity="one">%d enhet</item>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Rensa alla"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Hantera"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkommande"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Ljudlösa aviseringar"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Aviseringar med vibration eller ljud"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tryck för att starta om appen i helskärmsläge."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-bubblor"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Fler menyalternativ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Lägg tillbaka på stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Hantera"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g> och <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> fler"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listan med alla kontroller kunde inte läsas in."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Lägg till i enhetsstyrning"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Lägg till i Favoriter"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> föreslår att du lägger till kontrollen i dina favoriter."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Lägg till"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Förslag från <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Snabbkontroller uppdaterade"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden innehåller bokstäver eller symboler"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifiera <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 20e0325..51d1a17 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -89,9 +89,10 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ondoa picha ya skrini"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Onyesho la kukagua picha ya skrini"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Kinasa Skrini"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Ungependa kuanza kurekodi?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Inaporekodi, Mfumo wa Android unaweza kurekodi maelezo yoyote nyeti yanayoonekana kwenye skrini au yanayochezwa kwenye kifaa chako. Hii ni pamoja na manenosiri, maelezo ya malipo, picha, ujumbe na sauti."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Wakati wa kurekodi, Mfumo wa Android unaweza kusana maelezo yoyote nyeti yanayoonekana kwenye skrini au yanayochezwa kwenye kifaa chako. Hii ni pamoja na manenosiri, maelezo ya malipo, picha, ujumbe na sauti."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Rekodi sauti"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Sauti ya kifaa"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sauti kutoka kwenye kifaa chako, kama vile muziki, simu na milio ya simu"</string>
@@ -509,8 +510,9 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Futa zote"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Dhibiti"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Simu inayoingia"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Arifa zisizo na sauti"</string>
- <string name="notification_section_header_alerting" msgid="3168140660646863240">"Arifa za ilani"</string>
+ <string name="notification_section_header_alerting" msgid="3168140660646863240">"Arifa za kuarifu"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Mazungumzo"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Futa arifa zote zisizo na sauti"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kipengele cha Usinisumbue kimesitisha arifa"</string>
@@ -708,7 +710,7 @@
<string name="notification_alert_title" msgid="7629202599338071971">"Kutoa arifa"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Kiputo"</string>
<string name="notification_channel_summary_low" msgid="7300447764759926720">"Hukusaidia kuwa makini bila sauti au mtetemo."</string>
- <string name="notification_channel_summary_default" msgid="3539949463907902037">"Hupata umakinifu wako kwa sauti na mtetemo."</string>
+ <string name="notification_channel_summary_default" msgid="3539949463907902037">"Hupata umakinifu wako kwa sauti au mtetemo."</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="6298026344552480458">"Hupata umakinifu wako kwa sauti au mtetemo. Mazungumzo kutoka kiputo cha <xliff:g id="APP_NAME">%1$s</xliff:g> kwa chaguomsingi."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Huweka umakinifu wako kwenye maudhui haya kwa kutumia njia ya mkato ya kuelea."</string>
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Huonyeshwa sehemu ya juu ya mazungumzo na huonekana kama kiputo."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Wimbo hauna jina"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Gusa ili uzime na uwashe upya programu hii kisha nenda kwenye skrini nzima."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Mipangilio ya viputo vya <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Vipengee vya ziada"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Rejesha kwenye rafu"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Dhibiti"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka kwa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka kwa <xliff:g id="APP_NAME">%2$s</xliff:g> na nyingine<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Imeshindwa kupakia orodha ya vidhibiti vyote."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Weka kwenye vidhibiti vya vifaa"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Ongeza kwenye vipendwa"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> imependekeza kidhibiti hiki ili ukiongeze kwenye vipendwa vyako."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Weka"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Kimependekezwa na <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Umesasisha vidhibiti"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ina herufi au alama"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Thibitisha <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index e38fbaa..1bea16e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ஸ்கிரீன்ஷாட்டை நிராகரி"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ஸ்கிரீன்ஷாட்டின் மாதிரிக்காட்சி"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ஸ்கிரீன் ரெக்கார்டர்"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ரெக்கார்டிங்கைத் தொடங்கவா?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ரெக்கார்டு செய்யும்போது, உங்கள் திரையில் தோன்றக்கூடிய அல்லது சாதனத்தில் பிளே ஆகக்கூடிய ஏதேனும் அதிமுக்கியத் தகவலை Android சிஸ்டம் படமெடுக்க முடியும். கடவுச்சொற்கள், பேமெண்ட் தகவல், படங்கள், மெசேஜ்கள், ஆடியோ ஆகியவை இதில் அடங்கும்."</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"குமிழ் நிராகரிக்கப்பட்டது."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"அறிவிப்பு விவரம்."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"உடனடி அமைப்பு."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"லாக் ஸ்கிரீன்."</string>
@@ -432,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ஸ்கிரீன் ரெக்கார்டு"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"தொடங்கு"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"நிறுத்து"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"சாதனம்"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, மேல்நோக்கி ஸ்வைப் செய்க"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ஆப்ஸை வேகமாக மாற்ற, வலப்புறம் இழுக்கவும்"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"மேலோட்டப் பார்வையை நிலைமாற்று"</string>
@@ -511,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"எல்லாவற்றையும் அழி"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"அறிவிப்புகளை நிர்வகி"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"வரலாறு"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"உள்வருவது"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ஒலியில்லாத அறிவிப்புகள்"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"விழிப்பூட்டல் அறிவிப்புகள்"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string>
@@ -716,8 +716,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"உரையாடல் பிரிவின் மேற்பகுதியில் ஒரு குமிழாகக் காட்டப்படும்."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"உரையாடல் சார்ந்த குறிப்பிட்ட அமைப்புகளை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
@@ -990,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"தலைப்பு இல்லை"</string>
<string name="restart_button_description" msgid="6916116576177456480">"தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கலாம், முழுத்திரையில் பார்க்கலாம்."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> குமிழ்களுக்கான அமைப்புகள்"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ஓவர்ஃப்லோ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"மீண்டும் ஸ்டேக்கில் சேர்க்கவும்"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"நிர்வகி"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> இலிருந்து <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> மற்றும் மேலும் <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ஆப்ஸிலிருந்து வந்துள்ள அறிவிப்பு: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1030,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"பவர் மெனுவில் இருந்து அணுகுவதற்கான கட்டுப்பாடுகளைத் தேர்ந்தெடுக்கலாம்"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"கட்டுப்பாடுகளை மறுவரிசைப்படுத்த அவற்றைப் பிடித்து இழுக்கவும்"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"கட்டுப்பாடுகள் அனைத்தும் அகற்றப்பட்டன"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"மாற்றங்கள் சேமிக்கப்படவில்லை"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"எல்லா கட்டுப்பாடுகளின் பட்டியலை ஏற்ற முடியவில்லை."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"பிற"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"சாதனக் கட்டுப்பாடுகளில் சேர்த்தல்"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"விருப்பமானவையில் சேர்"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"இந்தக் கட்டுப்பாட்டை உங்களுக்கு விருப்பமானவையில் சேர்க்கும்படி <xliff:g id="APP">%s</xliff:g> பரிந்துரைக்கிறார்."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"சேர்"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ஆப்ஸால் பரிந்துரைக்கப்பட்டது"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"கட்டுப்பாடுகள் மாற்றப்பட்டன"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"பின்னில் எழுத்துகள் அல்லது குறிகள் உள்ளன"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ஐச் சரிபார்த்தல்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ddeab71..42afdcf 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -63,8 +63,8 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"అనుమతించు"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB డీబగ్గింగ్కి అనుమతి లేదు"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ఈ పరికరానికి ప్రస్తుతం సైన్ ఇన్ చేసిన వినియోగదారు USB డీబగ్గింగ్ ఆన్ చేయలేరు. ఈ ఫీచర్ ఉపయోగించడానికి, ప్రాథమిక వినియోగదారుకి మారాలి."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"ఈ నెట్వర్క్ పై వైర్లెస్ డీబగ్గింగ్ను అనుమతిస్తారా?"</string>
- <string name="wifi_debugging_message" msgid="5461204211731802995">"నెట్వర్క్ పేరు (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi చిరునామా (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"ఈ నెట్వర్క్ ద్వారా వైర్లెస్ డీబగ్గింగ్ను అనుమతించాలా?"</string>
+ <string name="wifi_debugging_message" msgid="5461204211731802995">"నెట్వర్క్ పేరు (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi అడ్రస్ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ఈ నెట్వర్క్ నుండి ఎల్లప్పుడూ అనుమతించు"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"అనుమతించు"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"వైర్లెస్ డీబగ్గింగ్కి అనుమతి లేదు"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"స్క్రీన్షాట్ను మూసివేస్తుంది"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"స్క్రీన్షాట్ ప్రివ్యూ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"స్క్రీన్ రికార్డర్"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్గోయింగ్ నోటిఫికేషన్"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"రికార్డింగ్ను ప్రారంభించాలా?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నైనా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, చెల్లింపు వివరాలు, ఫోటోలు, మెసేజ్లు, ఆడియో ఉంటాయి."</string>
@@ -97,7 +98,7 @@
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే సంగీతం, కాల్లు, రింగ్టోన్ల వంటి ధ్వనులు"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"మైక్రోఫోన్"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"పరికరం ఆడియో, మైక్రోఫోన్"</string>
- <string name="screenrecord_start" msgid="330991441575775004">"ప్రారంభం"</string>
+ <string name="screenrecord_start" msgid="330991441575775004">"ప్రారంభించు"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"స్క్రీన్ రికార్డింగ్ చేయబడుతోంది"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"స్క్రీన్, ఆడియో రికార్డింగ్ చేయబడుతున్నాయి"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"స్క్రీన్పై తాకే స్థానాలను చూపు"</string>
@@ -255,8 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"నోటిఫికేషన్ తీసివేయబడింది."</string>
- <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
- <skip />
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"బబుల్ విస్మరించబడింది."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"నోటిఫికేషన్ షేడ్."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"శీఘ్ర సెట్టింగ్లు."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"లాక్ స్క్రీన్."</string>
@@ -368,7 +368,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"స్థానం ఆఫ్లో ఉంది"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ప్రసార మాధ్యమ పరికరం"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
- <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"అత్యవసర కాల్లు మాత్రమే"</string>
+ <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ఎమర్జెన్సీ కాల్స్ మాత్రమే"</string>
<string name="quick_settings_settings_label" msgid="2214639529565474534">"సెట్టింగ్లు"</string>
<string name="quick_settings_time_label" msgid="3352680970557509303">"సమయం"</string>
<string name="quick_settings_user_label" msgid="1253515509432672496">"నేను"</string>
@@ -389,7 +389,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi కనెక్ట్ కాలేదు"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ప్రకాశం"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"ఆటోమేటిక్"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"రంగులను అటుఇటు మార్చు"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"కలర్ మార్పిడి"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"రంగు సవరణ మోడ్"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"మరిన్ని సెట్టింగ్లు"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"పూర్తయింది"</string>
@@ -420,7 +420,7 @@
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"సూర్యోదయం వరకు"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g>కి"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> వరకు"</string>
- <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ముదురు రంగు థీమ్"</string>
+ <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ముదురు రంగు రూపం"</string>
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"బ్యాటరీ సేవర్"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"సూర్యాస్తమయానికి"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"సూర్యోదయం వరకు"</string>
@@ -510,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"అన్నీ క్లియర్ చేయండి"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"నిర్వహించండి"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"చరిత్ర"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"ఇన్కమింగ్"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"నిశ్శబ్ద నోటిఫికేషన్లు"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"అలర్ట్ చేసే నోటిఫికేషన్లు"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string>
@@ -855,7 +856,7 @@
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"టైల్ల క్రమం మార్చడానికి వాటిని పట్టుకుని, లాగండి"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"తీసివేయడానికి ఇక్కడికి లాగండి"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"మీ వద్ద కనీసం <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> టైల్లు ఉండాలి"</string>
- <string name="qs_edit" msgid="5583565172803472437">"సవరించు"</string>
+ <string name="qs_edit" msgid="5583565172803472437">"ఎడిట్ చేయండి"</string>
<string name="tuner_time" msgid="2450785840990529997">"సమయం"</string>
<string-array name="clock_options">
<item msgid="3986445361435142273">"గంటలు, నిమిషాలు మరియు సెకన్లను చూపు"</item>
@@ -961,12 +962,12 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"యాప్ (<xliff:g id="ID_1">%s</xliff:g>) ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"స్వయంచాలక నియమం లేదా యాప్ ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> వరకు"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"ఉంచు"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"భర్తీ చేయి"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"నేపథ్యంలో అమలు అవుతున్న ఆప్లు"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"బ్యాటరీ మరియు డేటా వినియోగ వివరాల కోసం నొక్కండి"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"మొబైల్ డేటాను ఆఫ్ చేయాలా?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"మీకు <xliff:g id="CARRIER">%s</xliff:g> ద్వారా డేటా లేదా ఇంటర్నెట్కు యాక్సెస్ ఉండదు. Wi-Fi ద్వారా మాత్రమే ఇంటర్నెట్ అందుబాటులో ఉంటుంది."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"\"<xliff:g id="CARRIER">%s</xliff:g>\" ద్వారా మీకు డేటా లేదా ఇంటర్నెట్కు యాక్సెస్ ఉండదు. Wi-Fi ద్వారా మాత్రమే ఇంటర్నెట్ అందుబాటులో ఉంటుంది."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"మీ క్యారియర్"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"అనుమతి అభ్యర్థనకు ఒక యాప్ అడ్డు తగులుతున్నందున సెట్టింగ్లు మీ ప్రతిస్పందనను ధృవీకరించలేకపోయాయి."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> స్లైస్లను చూపించడానికి <xliff:g id="APP_0">%1$s</xliff:g>ని అనుమతించండి?"</string>
@@ -988,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ఈ యాప్ను పునఃప్రారంభించేలా నొక్కి, ఆపై పూర్తి స్క్రీన్లోకి వెళ్లండి."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> బబుల్స్ సెట్టింగ్లు"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ఓవర్ఫ్లో"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"స్ట్యాక్కు తిరిగి జోడించండి"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"నిర్వహించండి"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> మరియు మరో <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1028,13 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"పవర్ మెనూ నుండి యాక్సెస్ చేయడానికి నియంత్రణలను ఎంచుకోండి"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"నియంత్రణల క్రమం మార్చడానికి పట్టుకుని&amp, లాగండి"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"అన్ని నియంత్రణలు తీసివేయబడ్డాయి"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"మార్పులు సేవ్ చేయబడలేదు"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"అన్ని నియంత్రణలు గల జాబితాను లోడ్ చేయలేకపోయాము."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ఇతరం"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"పరికరం నియంత్రణలకు జోడించడం"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"ఇష్టమైనవాటికి జోడించు"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"మీ ఇష్టమైనవాటికి జోడించడానికి <xliff:g id="APP">%s</xliff:g> ఈ కంట్రోల్ను సూచించింది."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"జోడించండి"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ద్వారా సూచించబడింది"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"నియంత్రణలు అప్డేట్ అయ్యాయి"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"పిన్ అక్షరాలను లేదా చిహ్నాలను కలిగి ఉంది"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ను వెరిఫై చేయండి"</string>
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index ded2f50..df8b06d 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="844249465483874817">"చిత్రంలో చిత్రం"</string>
+ <string name="notification_channel_tv_pip" msgid="844249465483874817">"పిక్చర్-ఇన్-పిక్చర్"</string>
<string name="pip_notification_unknown_title" msgid="4413256731340767259">"(శీర్షిక లేని ప్రోగ్రామ్)"</string>
<string name="pip_close" msgid="5775212044472849930">"PIPని మూసివేయి"</string>
<string name="pip_fullscreen" msgid="3877997489869475181">"పూర్తి స్క్రీన్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 332155f..ee6b422 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -38,7 +38,7 @@
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"เปิด"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"เปิดโหมดประหยัดแบตเตอรี่"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"การตั้งค่า"</string>
- <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"WiFi"</string>
+ <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"หมุนหน้าจออัตโนมัติ"</string>
<string name="status_bar_settings_mute_label" msgid="914392730086057522">"ปิดเสียง"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="2151934479226017725">"อัตโนมัติ"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ปิดภาพหน้าจอ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ตัวอย่างภาพหน้าจอ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมอัดหน้าจอ"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"เริ่มบันทึกเลยไหม"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ขณะบันทึก ระบบ Android จะบันทึกข้อมูลที่ละเอียดอ่อนที่ปรากฏบนหน้าจอหรือเล่นในอุปกรณ์ได้ ซึ่งรวมถึงรหัสผ่าน ข้อมูลการชำระเงิน รูปภาพ ข้อความ และเสียง"</string>
@@ -373,7 +374,7 @@
<string name="quick_settings_user_label" msgid="1253515509432672496">"ฉัน"</string>
<string name="quick_settings_user_title" msgid="8673045967216204537">"ผู้ใช้"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ผู้ใช้ใหม่"</string>
- <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
+ <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ไม่ได้เชื่อมต่อ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ไม่มีเครือข่าย"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ปิด WiFi"</string>
@@ -388,7 +389,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ไม่ได้เชื่อมต่อ Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ความสว่าง"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"อัตโนมัติ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"สลับสี"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"กลับสี"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"โหมดการแก้ไขสี"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"การตั้งค่าเพิ่มเติม"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"เสร็จสิ้น"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ล้างทั้งหมด"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"จัดการ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ประวัติ"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"เข้ามาใหม่"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"การแจ้งเตือนแบบไม่มีเสียง"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"มีการแจ้งเตือน"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"การสนทนา"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"แอปที่กำลังทำงานในเบื้องหลัง"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"แตะเพื่อดูรายละเอียดเกี่ยวกับแบตเตอรี่และปริมาณการใช้อินเทอร์เน็ต"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ปิดอินเทอร์เน็ตมือถือไหม"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"คุณจะใช้เน็ตมือถือหรืออินเทอร์เน็ตผ่าน <xliff:g id="CARRIER">%s</xliff:g> ไม่ได้ แต่จะใช้ผ่าน Wi-Fi ได้เท่านั้น"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"คุณจะใช้เน็ตมือถือหรืออินเทอร์เน็ตผ่าน \"<xliff:g id="CARRIER">%s</xliff:g>\" ไม่ได้ แต่จะใช้ผ่าน Wi-Fi ได้เท่านั้น"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ผู้ให้บริการของคุณ"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"เนื่องจากแอปหนึ่งได้บดบังคำขอสิทธิ์ ระบบจึงไม่สามารถยืนยันคำตอบของคุณสำหรับการตั้งค่าได้"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"อนุญาตให้ <xliff:g id="APP_0">%1$s</xliff:g> แสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"แตะเพื่อรีสตาร์ทแอปนี้และแสดงแบบเต็มหน้าจอ"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"การตั้งค่าบับเบิล <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"รายการเพิ่มเติม"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"เพิ่มกลับไปที่สแต็ก"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"จัดการ"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g> และอีก <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> รายการ"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"โหลดรายการตัวควบคุมทั้งหมดไม่ได้"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"เพิ่มไปยังระบบควบคุมอุปกรณ์"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"เพิ่มในรายการโปรด"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> แนะนำให้เพิ่มการควบคุมนี้ในรายการโปรด"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"เพิ่ม"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"แนะนำโดย <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"อัปเดตตัวควบคุมแล้ว"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ประกอบด้วยตัวอักษรหรือสัญลักษณ์"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"ยืนยัน <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d344a1e..db26407 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"I-dismiss ang screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Preview ng screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder ng Screen"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pinoproseso screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Simulang Mag-record?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Habang nagre-record, puwedeng ma-capture ng Android System ang anumang sensitibong impormasyong nakikita sa iyong screen o nagpe-play sa device mo. Kasama dito ang mga password, impormasyon sa pagbabayad, mga larawan, mensahe, at audio."</string>
@@ -435,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Mag-swipe pataas upang lumipat ng app"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"I-drag pakanan para mabilisang magpalipat-lipat ng app"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"I-toggle ang Overview"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Nasingil na"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Tapos nang mag-charge"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nagcha-charge"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hanggang mapuno"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Hindi nagcha-charge"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"I-clear lahat"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Pamahalaan"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Papasok"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Mga silent na notification"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Mga nag-aalertong notification"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Mga Pag-uusap"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Walang pamagat"</string>
<string name="restart_button_description" msgid="6916116576177456480">"I-tap para i-restart ang app na ito at mag-full screen."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Mga setting para sa mga bubble ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Idagdag ulit sa stack"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Pamahalaan"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g> at <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> pa"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Hindi ma-load ang listahan ng lahat ng control."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Idagdag sa mga kontrol ng device"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Idagdag sa mga paborito"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g> ang kontrol na ito na idagdag sa iyong mga paborito."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Idagdag"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Na-update na ang mga kontrol"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"May mga titik o simbolo ang PIN"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"I-verify ang <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 7e9280d..1077905 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ekran görüntüsünü kapat"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran görüntüsü önizlemesi"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Kayıt Başlatılsın mı?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Kayıt sırasında Android Sistemi, ekranınızda görünen veya cihazınızda oynatılan hassas bilgileri yakalayabilir. Buna şifreler, ödeme bilgileri, fotoğraflar, mesajlar ve sesler dahildir."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Tümünü temizle"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Yönet"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Geçmiş"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gelen"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Sessiz bildirimler"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Uyaran bildirimler"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string>
@@ -950,7 +952,7 @@
<string name="instant_apps_message_with_help" msgid="1816952263531203932">"Uygulama yüklenmeden açıldı. Daha fazla bilgi için dokunun."</string>
<string name="app_info" msgid="5153758994129963243">"Uygulama bilgisi"</string>
<string name="go_to_web" msgid="636673528981366511">"Tarayıcıya git"</string>
- <string name="mobile_data" msgid="4564407557775397216">"Mobil veriler"</string>
+ <string name="mobile_data" msgid="4564407557775397216">"Mobil veri"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>, <xliff:g id="CARRIER_NAME">%1$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Kablosuz bağlantı kapalı"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıksız"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Bu uygulamayı yeniden başlatmak ve tam ekrana geçmek için dokunun."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> baloncukları için ayarlar"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Taşma"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Yığına geri ekle"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Yönet"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ve diğer <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Tüm kontrollerin listesi yüklenemedi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz denetimlerine ekle"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Favorilere ekle"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>, bu kontrolü favorilerinize eklemenizi önerdi."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Ekle"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tarafından önerildi"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Denetimler güncellendi"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN, harf veya simge içerir"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5bb59eb..2ad5465 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -88,7 +88,8 @@
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Додаток або адміністратор вашої організації не дозволяють робити знімки екрана"</string>
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Закрити знімок екрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Перегляд знімка екрана"</string>
- <string name="screenrecord_name" msgid="2596401223859996572">"Створення знімків екрана"</string>
+ <string name="screenrecord_name" msgid="2596401223859996572">"Відеозапис екрана"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Почати запис?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Під час запису система Android може фіксувати будь-яку конфіденційну інформацію, яка з\'являється на екрані або відтворюється на пристрої, зокрема паролі, платіжну інформацію, фотографії, повідомлення та звуки."</string>
@@ -515,6 +516,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Очистити все"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Керувати"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Історія"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Нові"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Беззвучні сповіщення"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Сповіщення зі звуком чи вібрацією"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string>
@@ -997,6 +999,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Натисніть, щоб перезапустити додаток і перейти в повноекранний режим."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налаштування спливаючих чатів від додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Додаткове меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Додати в список"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Налаштувати"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"Cповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"Сповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g> (і ще <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
@@ -1043,8 +1047,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не вдалося завантажити список усіх елементів керування."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Додати до елементів керування пристроями"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Додати у вибране"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> пропонує додати цей елемент керування у вибране."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Додати"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Запропоновано додатком <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Елементи керування оновлено"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код містить літери чи символи"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>: підтвердити"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 6129f2a..b8c0172 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"اسکرین شاٹ برخاست کریں"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"اسکرین شاٹ کا پیش منظر"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"سکرین ریکارڈر"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"ریکارڈنگ شروع کریں؟"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"ریکارڈ کرنے کے دوران، Android سسٹم آپ کی اسکرین پر نظر آنے والی یا آپ کے آلہ پر چلنے والی کسی بھی حساس معلومات کو کیپچر کر سکتا ہے۔ اس میں پاس ورڈز، ادائیگی کی معلومات، تصاویر، پیغامات اور آڈیو شامل ہیں۔"</string>
@@ -99,7 +100,7 @@
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"آلہ کا آڈیو اور مائیکروفون"</string>
<string name="screenrecord_start" msgid="330991441575775004">"شروع کریں"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"ریکارڈنگ اسکرین"</string>
- <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"ریکارڈنگ اسکرین اور آڈیو"</string>
+ <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"اسکرین اور آڈیو کی ریکارڈنگ ہو رہی ہے"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"اسکرین پر کئے گئے ٹچز دکھائیں"</string>
<string name="screenrecord_stop_text" msgid="6549288689506057686">"روکنے کے لیے تھپتھپائیں"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"روکیں"</string>
@@ -255,7 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"اطلاع مسترد ہوگئی۔"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"بلبلہ مسترد کر دیا گیا۔"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"بلبلہ برخاست کر دیا گیا۔"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"اطلاعاتی شیڈ۔"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"فوری ترتیبات۔"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"مقفل اسکرین۔"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"نظم کریں"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"سرگزشت"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"اِن کمنگ"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"اطلاعات خاموش کریں"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"متنبہ کرنے کی اطلاعات"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"کوئی عنوان نہیں ہے"</string>
<string name="restart_button_description" msgid="6916116576177456480">"یہ ایپ دوبارہ شروع کرنے کے لیے تھپتھپائیں اور پوری اسکرین پر جائیں۔"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> بلبلوں کے لیے ترتیبات"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"اوورفلو"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"انبار میں واپس شامل کریں"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"نظم کریں"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> کی جانب سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> اور <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مزید سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"تمام کنٹرولز کی فہرست لوڈ نہیں کی جا سکی۔"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"آلہ کے کنٹرولز میں شامل کریں"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"پسندیدگیوں میں شامل کریں"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> نے آپ کی پسندیدگیوں میں شامل کرنے کے ليے یہ کنٹرول تجویز کیا۔"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"شامل کریں"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> کی طرف سے تجویز کردہ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"کنٹرولز اپ ڈیٹ کیے گئے"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN میں حروف یا علامات شامل ہیں"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> کی تصدیق کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index e9b0083..1d91bb7 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Ruxsat berish"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB orqali nosozliklarni tuzatishga ruxsat berilmagan"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Ayni paytda ushbu qurilmaga o‘z hisobi bilan kirgan foydalanuvchi USB orqali nosozliklarni aniqlash funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun asosiy foydalanuvchi profiliga o‘ting."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu tarmoqda Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Tarmoq nomi (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Manzil (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Bu tarmoqda doim ruxsat etilsin"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Ruxsat"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Skrinshotni yopish"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skrinshotga razm solish"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Yozib olish boshlansinmi?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Yozib olishda Android tizimi ekraningizda koʻringan yoki qurilmangizda ijro etilgan maxfiy axborotni ham yozib olishi mumkin. Bunga parollar, toʻlovga oid axborot, suratlar, xabarlar va audio kiradi."</string>
@@ -167,7 +168,7 @@
<string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Agar parolni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu qurilmadagi maʼlumotlar oʻchirib tashlanadi."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu foydalanuvchi oʻchirib tashlanadi."</string>
- <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu ishchi profil va undagi maʼlumotlar oʻchirib tashlanadi."</string>
+ <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
<string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Yopish"</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmoq izi skaneriga tegining"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmoq izi belgisi"</string>
@@ -255,7 +256,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Xabarnoma e‘tiborsiz qoldirildi."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulutchali xabar yopildi."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulutcha yopildi."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Xabarnoma soyasi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tezkor sozlamalar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Qulflash ekrani."</string>
@@ -413,7 +414,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> sarflandi"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Cheklov: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Ishchi profil"</string>
+ <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Ish profili"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Tungi rejim"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Kunbotarda yoqish"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Quyosh chiqqunicha"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Boshqarish"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Tarix"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Kiruvchi"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Sokin bildirishnomalar"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Bildirishnomalarning yuborilishi"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string>
@@ -649,7 +651,7 @@
<string name="show_demo_mode" msgid="3677956462273059726">"Demo rejimni ko‘rsatish"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Signal"</string>
- <string name="status_bar_work" msgid="5238641949837091056">"Ishchi profil"</string>
+ <string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string>
<string name="add_tile" msgid="6239678623873086686">"Tezkor sozlamalar tugmasini qo‘shish"</string>
<string name="broadcast_tile" msgid="5224010633596487481">"Translatsiya tugmasi"</string>
@@ -659,7 +661,7 @@
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Tezkor sozlamalar, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
- <string name="accessibility_managed_profile" msgid="4703836746209377356">"Ishchi profil"</string>
+ <string name="accessibility_managed_profile" msgid="4703836746209377356">"Ish profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diqqat!"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner yordamida siz Android foydalanuvchi interfeysini tuzatish va o‘zingizga moslashtirishingiz mumkin. Ushbu tajribaviy funksiyalar o‘zgarishi, buzilishi yoki keyingi versiyalarda olib tashlanishi mumkin. Ehtiyot bo‘lib davom eting."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Ushbu tajribaviy funksiyalar o‘zgarishi, buzilishi yoki keyingi versiyalarda olib tashlanishi mumkin. Ehtiyot bo‘lib davom eting."</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Bu ilovani qaytadan ishga tushirish va butun ekranga ochish uchun bosing."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> bulutchalari uchun sozlamalar"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Kengaytirilgan"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Yana toʻplamga kiritish"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Boshqarish"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ilovasidan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> va yana <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ta bildirishnoma"</string>
@@ -1027,12 +1031,12 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Quvvat tugmasi menyusida chiqadigan boshqaruv elementlarini tanlang"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Boshqaruv elementlarini qayta tartiblash uchun ushlab torting"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Barcha boshqaruv elementlari olib tashlandi"</string>
- <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Oʻzgartirishlar saqlanmadi"</string>
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Oʻzgarishlar saqlanmadi"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Boshqaruv elementlarining barchasi yuklanmadi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Qurilma boshqaruv elementlariga kiritish"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Saralanganlarga kiritish"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ilovasi bu sozlamani saralanganlarga kiritishni taklif qildi."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Kiritish"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> taklif etgan"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Boshqaruv elementlari yangilandi"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kod harflar va belgilardan iborat boʻladi"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Tekshirish: <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3b5e8b1..44f1497 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Đóng ảnh chụp màn hình"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Xem trước ảnh chụp màn hình"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Trình ghi màn hình"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Bắt đầu ghi?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Trong khi ghi, Hệ thống Android có thể ghi lại mọi thông tin nhạy cảm hiển thị trên màn hình hoặc phát trên thiết bị của bạn. Những thông tin này bao gồm mật khẩu, thông tin thanh toán, ảnh, thông báo và âm thanh."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Xóa tất cả"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Quản lý"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Lịch sử"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Hiển thị gần đây"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Thông báo im lặng"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Thông báo cảnh báo"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Cuộc trò chuyện"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Ứng dụng đang chạy trong nền"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Nhấn để biết chi tiết về mức sử dụng dữ liệu và pin"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Tắt dữ liệu di động?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua chế độ <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"nhà mạng của bạn"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Vì ứng dụng đang che khuất yêu cầu cấp quyền nên Cài đặt không thể xác minh câu trả lời của bạn."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Cho phép <xliff:g id="APP_0">%1$s</xliff:g> hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Không có tiêu đề"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Nhấn để khởi động lại ứng dụng này và xem ở chế độ toàn màn hình."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Tùy chọn cài đặt cho bong bóng trò chuyện <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Trình đơn mục bổ sung"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Thêm lại vào ngăn xếp"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Quản lý"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> của <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g> và <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> bong bóng khác"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Không thể tải danh sách tất cả tùy chọn điều khiển."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Thêm vào mục điều khiển thiết bị"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Thêm vào mục yêu thích"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> đã đề xuất thêm tùy chọn điều khiển này vào mục yêu thích của bạn."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Thêm"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Do <xliff:g id="APP">%s</xliff:g> đề xuất"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Đã cập nhật các tùy chọn điều khiển"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Mã PIN chứa các ký tự hoặc ký hiệu"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Xác minh <xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index f547280..0ed76b7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"允许"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"不允许使用 USB 调试功能"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"目前已登录此设备的用户无法开启 USB 调试功能。要使用此功能,请切换为主要用户的帐号。"</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"要在此网络上允许无线调试吗?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"要允许在此网络上进行无线调试吗?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"网络名称 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWLAN 地址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"在此网络上始终允许"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"允许"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"关闭屏幕截图"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"屏幕截图预览"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"要开始录制吗?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"在录制内容时,Android 系统可以捕捉到您屏幕上显示或设备中播放的敏感信息,其中包括密码、付款信息、照片、消息和音频。"</string>
@@ -192,7 +193,7 @@
<string name="accessibility_data_two_bars" msgid="4576231688545173059">"数据信号强度为两格。"</string>
<string name="accessibility_data_three_bars" msgid="3036562180893930325">"数据信号强度为三格。"</string>
<string name="accessibility_data_signal_full" msgid="283507058258113551">"数据信号满格。"</string>
- <string name="accessibility_wifi_name" msgid="4863440268606851734">"已连接到<xliff:g id="WIFI">%s</xliff:g>。"</string>
+ <string name="accessibility_wifi_name" msgid="4863440268606851734">"已连接到“<xliff:g id="WIFI">%s</xliff:g>”。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已连接到 <xliff:g id="CAST">%s</xliff:g>。"</string>
<string name="accessibility_no_wimax" msgid="2014864207473859228">"无 WiMAX 信号。"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"历史记录"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"无声通知"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"提醒通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"对话"</string>
@@ -713,7 +715,7 @@
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"通过可链接到这项内容的浮动快捷方式吸引您的注意。"</string>
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"以对话泡形式显示在对话部分顶部。"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"设置"</string>
- <string name="notification_priority_title" msgid="2079708866333537093">"优先级"</string>
+ <string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
<string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话专用设置"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近没有对话泡"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"此处会显示最近的对话泡和已关闭的对话泡"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"无标题"</string>
<string name="restart_button_description" msgid="6916116576177456480">"点按即可重启此应用并进入全屏模式。"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>对话泡的设置"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"菜单"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"重新加入叠放"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g>和另外 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 个应用:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"无法加载所有控件的列表。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"添加到设备控制器"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"添加到收藏夹"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>建议将此控件添加到您的收藏夹。"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"添加"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"来自<xliff:g id="APP">%s</xliff:g>的建议"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"控件已更新"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 码由字母或符号组成"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"验证<xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5f5b4cb..9a7d951 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -65,7 +65,7 @@
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"目前登入此裝置的使用者無法啟用 USB 偵錯功能。如要使用此功能,請切換至主要使用者。"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"要在此網絡上允許無線偵錯功能嗎?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"網絡名稱 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi 地址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
- <string name="wifi_debugging_always" msgid="2968383799517975155">"在此網絡上永遠允許"</string>
+ <string name="wifi_debugging_always" msgid="2968383799517975155">"一律允許在此網絡上執行"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"允許"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"不允許無線偵錯功能"</string>
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"目前登入此裝置的使用者無法啟用無線偵錯功能。如要使用此功能,請切換至主要使用者。"</string>
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"關閉螢幕截圖"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄影工具"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"要開始錄影嗎?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"錄影時,Android 系統可擷取螢幕上顯示或裝置播放的任何敏感資料,包括密碼、付款資料、相片、訊息和音訊。"</string>
@@ -99,7 +100,7 @@
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"裝置音訊和麥克風"</string>
<string name="screenrecord_start" msgid="330991441575775004">"開始"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"正在錄影螢幕畫面"</string>
- <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"錄影螢幕畫面和音訊"</string>
+ <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"正在錄製螢幕畫面和音訊"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"顯示輕觸螢幕的位置"</string>
<string name="screenrecord_stop_text" msgid="6549288689506057686">"輕按即可停止"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"停止"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"靜音通知"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"提醒通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
@@ -965,7 +967,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"正在背景中執行的應用程式"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"輕按即可查看電池和數據用量詳情"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉流動數據嗎?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"您將無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用流動數據或互聯網,只可透過 Wi-Fi 才能連接互聯網。"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"您無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用流動數據或互聯網。如要使用互聯網,您必須連接 Wi-Fi。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"您的流動網絡供應商"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"由於某個應用程式已阻擋權限要求畫面,因此「設定」應用程式無法驗證您的回應。"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊嗎?"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="restart_button_description" msgid="6916116576177456480">"輕按即可重新開啟此應用程式並放大至全螢幕。"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」小視窗設定"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"顯示更多"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"加回堆疊"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"來自「<xliff:g id="APP_NAME">%2$s</xliff:g>」的 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"來自「<xliff:g id="APP_NAME">%2$s</xliff:g>」及另外 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整控制項清單。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"加到裝置控制"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"加入至常用項目"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"「<xliff:g id="APP">%s</xliff:g>」建議將此控制項加入至常用項目。"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"由「<xliff:g id="APP">%s</xliff:g>」提供的建議"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 含有字母或符號"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"驗證<xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ba30f14..b1ba86a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"關閉螢幕截圖"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕錄影器"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"要開始錄製嗎?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"錄製螢幕畫面時,Android 系統可擷取螢幕上顯示或裝置播放的任何機密資訊,包括密碼、付款資訊、相片、訊息和音訊。"</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"靜音通知"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"快訊通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="restart_button_description" msgid="6916116576177456480">"輕觸即可重新啟動這個應用程式並進入全螢幕模式。"</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」對話框的設定"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"溢位"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"重新加入堆疊"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」和其他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整的控制項清單。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"新增至裝置控制"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"新增至常用控制項"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"「<xliff:g id="APP">%s</xliff:g>」建議你將這個控制項新增至常用控制項。"</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"來自「<xliff:g id="APP">%s</xliff:g>」的建議"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 碼含有字母或符號"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"驗證「<xliff:g id="DEVICE">%s</xliff:g>」"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2f8dad9..2fe904a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -89,6 +89,7 @@
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Cashisa isithombe-skrini"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ukubuka kuqala isithombe-skrini"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Irekhoda yesikrini"</string>
+ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Qala ukurekhoda?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"Ngenkathi irekhoda, Isistimu ye-Android ingathatha noma iluphi ulwazi olubucayi olubonakal kusikrini sakho noma oludlalwa kudivayisi yakho. Lokhu kufaka phakathi amaphasiwedi, ulwazi lokukhokha, izithombe, imilayezo, nomsindo."</string>
@@ -509,6 +510,7 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Sula konke"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Phatha"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Umlando"</string>
+ <string name="notification_section_header_incoming" msgid="5295312809341711367">"Okungenayo"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"Thulisa izaziso"</string>
<string name="notification_section_header_alerting" msgid="3168140660646863240">"Izaziso zokuxwayisa"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string>
@@ -987,6 +989,8 @@
<string name="music_controls_no_title" msgid="4166497066552290938">"Asikho isihloko"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Thepha ukuze uqale kabusha lolu hlelo lokusebenza uphinde uye kusikrini esigcwele."</string>
<string name="bubbles_settings_button_description" msgid="7324245408859877545">"Izilungiselelo zamabhamuza e-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Ukuphuphuma"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Engeza emuva kusitaki"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Phatha"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"I-<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"I-<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusukela ku-<xliff:g id="APP_NAME">%2$s</xliff:g> nokungu-<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ngaphezulu"</string>
@@ -1031,8 +1035,8 @@
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Uhlu lwazo zonke izilawuli alilayishekanga."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Engeza kuzilawuli zezinsiza"</string>
- <string name="controls_dialog_ok" msgid="7011816381344485651">"Engeza kuzintandokazi"</string>
- <string name="controls_dialog_message" msgid="6292099631702047540">"I-<xliff:g id="APP">%s</xliff:g> iphakamise lokhu kulawula ukwengeza kuzintandokazi zakho."</string>
+ <string name="controls_dialog_ok" msgid="2770230012857881822">"Engeza"</string>
+ <string name="controls_dialog_message" msgid="342066938390663844">"Kuphakanyiswe ngu-<xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Izilawuli zibuyekeziwe"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Iphinikhodi iqukethe amaletha namasimbui"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Qinisekisa i-<xliff:g id="DEVICE">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index d3256ef..c419594 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -154,5 +154,12 @@
<declare-styleable name="CaptionsToggleImageButton">
<attr name="optedOut" format="boolean" />
</declare-styleable>
+
+ <declare-styleable name="IlluminationDrawable">
+ <attr name="highlight" format="integer" />
+ <attr name="cornerRadius" format="dimension" />
+ <attr name="rippleMinSize" format="dimension" />
+ <attr name="rippleMaxSize" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 82eda31..837627c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -200,6 +200,7 @@
<color name="global_screenshot_button_icon">@color/GM2_blue_500</color>
<color name="global_screenshot_dismiss_background">#FFFFFF</color>
<color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
+ <color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
@@ -238,9 +239,14 @@
<color name="magnification_border_color">#FF9900</color>
+ <!-- media -->
+ <color name="media_primary_text">@android:color/white</color>
+ <color name="media_seekbar_progress">#c0ffffff</color>
+ <color name="media_disabled">#80ffffff</color>
+
<!-- controls -->
- <color name="control_primary_text">@color/GM2_grey_100</color>
- <color name="control_secondary_text">@color/GM2_grey_500</color>
+ <color name="control_primary_text">#E6FFFFFF</color>
+ <color name="control_secondary_text">#99FFFFFF</color>
<color name="control_default_foreground">@color/GM2_grey_500</color>
<color name="control_default_background">@color/GM2_grey_900</color>
<color name="control_list_popup_background">@*android:color/background_floating_material_dark</color>
@@ -256,4 +262,6 @@
<!-- Docked misalignment message -->
<color name="misalignment_text_color">#F28B82</color>
+
+ <color name="screenrecord_status_color">#E94235</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d2f64f9..1407574 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -530,6 +530,10 @@
<!-- ID for the camera that needs extra protection -->
<string translatable="false" name="config_protectedCameraId"></string>
+ <!-- Comma-separated list of packages to exclude from camera protection e.g.
+ "com.android.systemui,com.android.xyz" -->
+ <string translatable="false" name="config_cameraProtectionExcludedPackages"></string>
+
<!-- Flag to turn on the rendering of the above path or not -->
<bool name="config_enableDisplayCutoutProtection">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2cbb498..a3d32c1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -306,6 +306,7 @@
<dimen name="global_screenshot_bg_padding">20dp</dimen>
<dimen name="global_screenshot_bg_protection_height">400dp</dimen>
<dimen name="global_screenshot_x_scale">80dp</dimen>
+ <dimen name="screenshot_bg_protection_height">242dp</dimen>
<dimen name="screenshot_preview_elevation">6dp</dimen>
<dimen name="screenshot_offset_y">48dp</dimen>
<dimen name="screenshot_offset_x">16dp</dimen>
@@ -313,7 +314,7 @@
<dimen name="screenshot_dismiss_button_margin">8dp</dimen>
<dimen name="screenshot_action_container_offset_y">32dp</dimen>
<dimen name="screenshot_action_container_corner_radius">10dp</dimen>
- <dimen name="screenshot_action_container_padding_vertical">10dp</dimen>
+ <dimen name="screenshot_action_container_padding_vertical">16dp</dimen>
<dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
<dimen name="screenshot_action_container_padding_left">96dp</dimen>
<dimen name="screenshot_action_container_padding_right">8dp</dimen>
@@ -497,10 +498,10 @@
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
<dimen name="qs_header_tile_margin_horizontal">4dp</dimen>
+ <dimen name="qs_header_tile_margin_bottom">18dp</dimen>
<dimen name="qs_page_indicator_width">16dp</dimen>
<dimen name="qs_page_indicator_height">8dp</dimen>
<dimen name="qs_tile_icon_size">24dp</dimen>
- <dimen name="qs_tile_detail_padding">3dp</dimen>
<dimen name="qs_tile_text_size">12sp</dimen>
<dimen name="qs_tile_divider_height">1dp</dimen>
<dimen name="qs_panel_padding">16dp</dimen>
@@ -1042,6 +1043,10 @@
<dimen name="bottom_padding">48dp</dimen>
<dimen name="edge_margin">8dp</dimen>
+ <!-- The absolute side margins of quick settings -->
+ <dimen name="quick_settings_side_margins">16dp</dimen>
+ <dimen name="quick_settings_expanded_bottom_margin">16dp</dimen>
+ <dimen name="quick_settings_media_extra_bottom_margin">4dp</dimen>
<dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
@@ -1168,7 +1173,7 @@
<!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
<dimen name="bubble_expanded_default_height">180dp</dimen>
<!-- Default height of bubble overflow -->
- <dimen name="bubble_overflow_height">460dp</dimen>
+ <dimen name="bubble_overflow_height">480dp</dimen>
<!-- Bubble overflow padding when there are no bubbles -->
<dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
<!-- Padding of container for overflow bubbles -->
@@ -1229,12 +1234,12 @@
<!-- Size of media cards in the QSPanel carousel -->
<dimen name="qs_media_width">350dp</dimen>
- <dimen name="qs_media_padding">8dp</dimen>
+ <dimen name="qs_media_padding">16dp</dimen>
<dimen name="qs_media_panel_outer_padding">16dp</dimen>
- <dimen name="qs_media_corner_radius">10dp</dimen>
- <dimen name="qs_media_album_size">72dp</dimen>
+ <dimen name="qs_media_album_size">52dp</dimen>
<dimen name="qs_seamless_icon_size">20dp</dimen>
<dimen name="qqs_media_spacing">8dp</dimen>
+ <dimen name="qqs_horizonal_tile_padding_bottom">8dp</dimen>
<dimen name="magnification_border_size">5dp</dimen>
<dimen name="magnification_frame_move_short">5dp</dimen>
@@ -1275,6 +1280,10 @@
<dimen name="control_status_padding">3dp</dimen>
<fraction name="controls_toggle_bg_intensity">5%</fraction>
<fraction name="controls_dimmed_alpha">40%</fraction>
+ <dimen name="controls_setup_top_margin">16dp</dimen>
+ <dimen name="controls_setup_title">22sp</dimen>
+ <dimen name="controls_setup_subtitle">14sp</dimen>
+ <dimen name="controls_setup_vertical_padding">52dp</dimen>
<!-- Home Controls activity view detail panel-->
<dimen name="controls_activity_view_top_offset">100dp</dimen>
@@ -1317,7 +1326,10 @@
<dimen name="screenrecord_dialog_padding">18dp</dimen>
<dimen name="screenrecord_logo_size">24dp</dimen>
<dimen name="screenrecord_status_text_size">14sp</dimen>
- <dimen name="screenrecord_status_icon_radius">5dp</dimen>
+ <dimen name="screenrecord_status_icon_radius">7dp</dimen>
+ <dimen name="screenrecord_status_icon_width">21dp</dimen>
+ <dimen name="screenrecord_status_icon_height">17.5dp</dimen>
+ <dimen name="screenrecord_status_icon_bg_radius">8dp</dimen>
<dimen name="kg_user_switcher_text_size">16sp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 04640f4..09918e7 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -70,6 +70,26 @@
<item type="id" name="panel_alpha_animator_end_tag"/>
<item type="id" name="cross_fade_layer_type_changed_tag"/>
+ <item type="id" name="absolute_x_animator_tag"/>
+ <item type="id" name="absolute_x_animator_start_tag"/>
+ <item type="id" name="absolute_x_animator_end_tag"/>
+ <item type="id" name="absolute_x_current_value"/>
+
+ <item type="id" name="absolute_y_animator_tag"/>
+ <item type="id" name="absolute_y_animator_start_tag"/>
+ <item type="id" name="absolute_y_animator_end_tag"/>
+ <item type="id" name="absolute_y_current_value"/>
+
+ <item type="id" name="view_height_animator_tag"/>
+ <item type="id" name="view_height_animator_start_tag"/>
+ <item type="id" name="view_height_animator_end_tag"/>
+ <item type="id" name="view_height_current_value"/>
+
+ <item type="id" name="view_width_animator_tag"/>
+ <item type="id" name="view_width_animator_start_tag"/>
+ <item type="id" name="view_width_animator_end_tag"/>
+ <item type="id" name="view_width_current_value"/>
+
<!-- Whether the icon is from a notification for which targetSdk < L -->
<item type="id" name="icon_is_pre_L"/>
@@ -144,5 +164,13 @@
<!-- NotificationPanelView -->
<item type="id" name="notification_panel" />
+
+ <!-- Screen Recording -->
+ <item type="id" name="screen_recording_options" />
+ <item type="id" name="screen_recording_dialog_source_text" />
+ <item type="id" name="screen_recording_dialog_source_description" />
+
+ <item type="id" name="accessibility_action_controls_move_before" />
+ <item type="id" name="accessibility_action_controls_move_after" />
</resources>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index f35f351..b1e91c8 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -33,11 +33,6 @@
<!-- Maximum number of bubbles we allow in overflow before we dismiss the oldest one. -->
<integer name="bubbles_max_overflow">16</integer>
- <!-- Ratio of "left" end of status bar that will swipe to QQS. -->
- <integer name="qqs_split_fraction">3</integer>
- <!-- Ratio of "right" end of status bar that will swipe to QS. -->
- <integer name="qs_split_fraction">2</integer>
-
<integer name="magnification_default_scale">2</integer>
<!-- The position of the volume dialog on the screen.
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 96843f1..8bbcfa0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,6 +240,8 @@
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
<string name="screenrecord_name">Screen Recorder</string>
+ <!-- Processing screen recoding video in the background [CHAR LIMIT=30]-->
+ <string name="screenrecord_background_processing_label">Processing screen recording</string>
<!-- Description of the screen recording notification channel [CHAR LIMIT=NONE]-->
<string name="screenrecord_channel_description">Ongoing notification for a screen record session</string>
<!-- Title for the screen prompting the user to begin recording their screen [CHAR LIMIT=NONE]-->
@@ -1253,6 +1255,9 @@
<!-- The text for the notification history link. [CHAR LIMIT=40] -->
<string name="manage_notifications_history_text">History</string>
+ <!-- Section title for notifications that have recently appeared. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_incoming">Incoming</string>
+
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent notifications</string>
@@ -2608,6 +2613,10 @@
<!-- Text used for content description of settings button in the header of expanded bubble
view. [CHAR_LIMIT=NONE] -->
<string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
+ <!-- Content description for button that shows bubble overflow on click [CHAR LIMIT=NONE] -->
+ <string name="bubble_overflow_button_content_description">Overflow</string>
+ <!-- Action to add overflow bubble back to stack. [CHAR LIMIT=NONE] -->
+ <string name="bubble_accessibility_action_add_back">Add back to stack</string>
<!-- The text for the manage bubbles link. [CHAR LIMIT=NONE] -->
<string name="manage_bubbles_text">Manage</string>
<!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
@@ -2689,6 +2698,22 @@
<item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> controls added.</item>
</plurals>
+ <!-- Removed control in management screen [CHAR LIMIT=20] -->
+ <string name="controls_removed">Removed</string>
+
+ <!-- a11y state description for a control that is currently favorited [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_favorite">Favorited</string>
+ <!-- a11y state description for a control that is currently favorited with its position [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_favorite_position">Favorited, position <xliff:g id="number" example="1">%d</xliff:g></string>
+ <!-- a11y state description for a control that is currently not favorited [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_not_favorite">Unfavorited</string>
+ <!-- a11y action to favorite a control. It will read as "Double-tap to favorite" in screen readers [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_change_favorite">favorite</string>
+ <!-- a11y action to unfavorite a control. It will read as "Double-tap to unfavorite" in screen readers [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_change_unfavorite">unfavorite</string>
+ <!-- a11y action to move a control to the position specified by the parameter [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_move">Move to position <xliff:g id="number" example="1">%d</xliff:g></string>
+
<!-- Controls management controls screen default title [CHAR LIMIT=30] -->
<string name="controls_favorite_default_title">Controls</string>
<!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b5e7f4b..4f42370 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -620,6 +620,12 @@
<item name="rotateButtonScaleX">-1</item>
</style>
+ <style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small">
+ <item name="android:background">@null</item>
+ <item name="android:tint">@android:color/white</item>
+ <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
+ </style>
+
<!-- Used to style charging animation AVD animation -->
<style name="ChargingAnim" />
@@ -761,11 +767,11 @@
</style>
<style name="TextAppearance.ControlSetup.Title">
- <item name="android:textSize">25sp</item>
+ <item name="android:textSize">@dimen/controls_setup_title</item>
</style>
<style name="TextAppearance.ControlSetup.Subtitle">
- <item name="android:textSize">16sp</item>
+ <item name="android:textSize">@dimen/controls_setup_subtitle</item>
</style>
<!-- The attributes used for title (textAppearanceLarge) and message (textAppearanceMedium)
diff --git a/packages/SystemUI/res/xml/media_scene.xml b/packages/SystemUI/res/xml/media_scene.xml
new file mode 100644
index 0000000..f61b2b0
--- /dev/null
+++ b/packages/SystemUI/res/xml/media_scene.xml
@@ -0,0 +1,447 @@
+<?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
+ -->
+<MotionScene
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <Transition
+ app:constraintSetStart="@id/collapsed"
+ app:constraintSetEnd="@id/expanded"
+ app:duration="1000" >
+ <KeyFrameSet >
+ <KeyPosition
+ app:motionTarget="@+id/action0"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyPosition
+ app:motionTarget="@+id/action1"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyPosition
+ app:motionTarget="@+id/action2"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyPosition
+ app:motionTarget="@+id/action3"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyPosition
+ app:motionTarget="@+id/action4"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyPosition
+ app:motionTarget="@+id/media_progress_bar"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyAttribute
+ app:motionTarget="@id/media_progress_bar"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/media_progress_bar"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ <KeyPosition
+ app:motionTarget="@+id/notification_media_progress_time"
+ app:keyPositionType="pathRelative"
+ app:framePosition="70"
+ app:sizePercent="0.9" />
+ <KeyAttribute
+ app:motionTarget="@id/notification_media_progress_time"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/notification_media_progress_time"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ <KeyAttribute
+ app:motionTarget="@id/action0"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/action0"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ <KeyAttribute
+ app:motionTarget="@id/action1"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/action1"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ <KeyAttribute
+ app:motionTarget="@id/action2"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/action2"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ <KeyAttribute
+ app:motionTarget="@id/action3"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/action3"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ <KeyAttribute
+ app:motionTarget="@id/action4"
+ app:framePosition="0"
+ android:alpha="0.0" />
+ <KeyAttribute
+ app:motionTarget="@+id/action4"
+ app:framePosition="70"
+ android:alpha="0.0"/>
+ </KeyFrameSet>
+ </Transition>
+
+ <ConstraintSet android:id="@+id/expanded">
+ <Constraint
+ android:id="@+id/icon"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="18dp"
+ android:layout_marginTop="22dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ />
+
+ <Constraint
+ android:id="@+id/app_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="10dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="20dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toEndOf="@id/icon"
+ app:layout_constraintEnd_toStartOf="@id/media_seamless"
+ app:layout_constraintHorizontal_bias="0"
+ />
+
+ <Constraint
+ android:id="@+id/media_seamless"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_min="60dp"
+ android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ />
+
+ <Constraint
+ android:id="@+id/album_art"
+ android:layout_width="@dimen/qs_media_album_size"
+ android:layout_height="@dimen/qs_media_album_size"
+ android:layout_marginTop="14dp"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintTop_toBottomOf="@+id/app_name"
+ app:layout_constraintStart_toStartOf="parent"
+ />
+
+ <!-- Song name -->
+ <Constraint
+ android:id="@+id/header_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginTop="17dp"
+ android:layout_marginStart="16dp"
+ app:layout_constraintTop_toBottomOf="@+id/app_name"
+ app:layout_constraintStart_toEndOf="@id/album_art"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ app:layout_constraintHorizontal_bias="0"/>
+
+ <!-- Artist name -->
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginTop="3dp"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ app:layout_constraintHorizontal_bias="0"/>
+
+ <!-- Seek Bar -->
+ <Constraint
+ android:id="@+id/media_progress_bar"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ />
+
+ <Constraint
+ android:id="@+id/notification_media_progress_time"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="38dp"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ />
+
+ <Constraint
+ android:id="@+id/action0"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginTop="5dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toLeftOf="@id/action1"
+ app:layout_constraintTop_toBottomOf="@id/notification_media_progress_time"
+ app:layout_constraintBottom_toBottomOf="parent">
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action1"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
+ app:layout_constraintTop_toTopOf="@id/action0"
+ app:layout_constraintBottom_toBottomOf="parent">
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action2"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
+ app:layout_constraintTop_toTopOf="@id/action0"
+ app:layout_constraintBottom_toBottomOf="parent">
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action3"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
+ app:layout_constraintTop_toTopOf="@id/action0"
+ android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintBottom_toBottomOf="parent">
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintRight_toRightOf="@id/view_width"
+ app:layout_constraintTop_toTopOf="@id/action0"
+ app:layout_constraintBottom_toBottomOf="parent">
+ </Constraint>
+ </ConstraintSet>
+
+ <ConstraintSet android:id="@+id/collapsed">
+ <Constraint
+ android:id="@+id/icon"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:layout_marginStart="18dp"
+ android:layout_marginTop="22dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ />
+
+ <Constraint
+ android:id="@+id/app_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="10dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="20dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toEndOf="@id/icon"
+ app:layout_constraintEnd_toStartOf="@id/media_seamless"
+ app:layout_constraintHorizontal_bias="0"
+ />
+
+ <Constraint
+ android:id="@+id/media_seamless"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_min="60dp"
+ android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ />
+
+ <Constraint
+ android:id="@+id/album_art"
+ android:layout_width="@dimen/qs_media_album_size"
+ android:layout_height="@dimen/qs_media_album_size"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginBottom="24dp"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ />
+
+ <!-- Song name -->
+ <Constraint
+ android:id="@+id/header_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="17dp"
+ android:layout_marginStart="16dp"
+ app:layout_constraintTop_toBottomOf="@id/app_name"
+ app:layout_constraintBottom_toTopOf="@id/header_artist"
+ app:layout_constraintStart_toEndOf="@id/album_art"
+ app:layout_constraintEnd_toStartOf="@id/action0"
+ app:layout_constraintHorizontal_bias="0"/>
+
+ <!-- Artist name -->
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:layout_marginBottom="24dp"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintEnd_toStartOf="@id/action0"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"/>
+
+ <!-- Seek Bar -->
+ <Constraint
+ android:id="@+id/media_progress_bar"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:alpha="0.0"
+ app:layout_constraintTop_toBottomOf="@id/album_art"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ android:visibility="gone"
+ />
+
+ <Constraint
+ android:id="@+id/notification_media_progress_time"
+ android:alpha="0.0"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="35dp"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintTop_toBottomOf="@id/album_art"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/view_width"
+ android:visibility="gone"
+ />
+
+ <Constraint
+ android:id="@+id/action0"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginTop="16dp"
+ android:visibility="gone"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintTop_toBottomOf="@id/app_name"
+ app:layout_constraintLeft_toRightOf="@id/header_title"
+ app:layout_constraintRight_toLeftOf="@id/action1"
+ >
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action1"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginTop="18dp"
+ app:layout_constraintTop_toBottomOf="@id/app_name"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
+ >
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action2"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginTop="18dp"
+ app:layout_constraintTop_toBottomOf="@id/app_name"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
+ >
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action3"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginTop="18dp"
+ app:layout_constraintTop_toBottomOf="@id/app_name"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
+ >
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:visibility="gone"
+ android:layout_marginTop="18dp"
+ app:layout_constraintTop_toBottomOf="@id/app_name"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintRight_toRightOf="@id/view_width"
+ >
+ </Constraint>
+ </ConstraintSet>
+</MotionScene>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 26ef1d6..0350f2d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -28,57 +28,6 @@
void onInitialize(in Bundle params) = 12;
/**
- * @deprecated
- */
- void onBind(in ISystemUiProxy sysUiProxy) = 0;
-
- /**
- * Called once immediately prior to the first onMotionEvent() call, providing a hint to the
- * target the initial source of the subsequent motion events.
- *
- * @param downHitTarget is one of the {@link NavigationBarCompat.HitTarget}s
- *
- * @deprecated
- */
- void onPreMotionEvent(int downHitTarget) = 1;
-
- /**
- * Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
- * guarantees the following order of events:
- *
- * Normal gesture: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, UP
- * Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
- *
- * Once quick scrub is sent, then no further motion events will be provided.
- *
- * @deprecated
- */
- void onMotionEvent(in MotionEvent event) = 2;
-
- /**
- * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
- * sent the caller will stop sending any motion events and will no longer preemptively cancel
- * any recents animations started as a part of the motion event handling.
- *
- * @deprecated
- */
- void onQuickScrubStart() = 3;
-
- /**
- * Sent when the user stops actively scrubbing the nav bar to switch tasks.
- *
- * @deprecated
- */
- void onQuickScrubEnd() = 4;
-
- /**
- * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
- *
- * @deprecated
- */
- void onQuickScrubProgress(float progress) = 5;
-
- /**
* Sent when overview button is pressed to toggle show/hide of overview.
*/
void onOverviewToggle() = 6;
@@ -94,22 +43,8 @@
void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) = 8;
/**
- * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined
- * by passing the touch slop in the direction towards launcher from navigation bar. During and
- * after this event is sent the caller will continue to send motion events. The motion
- * {@param event} passed after the touch slop was exceeded will also be passed after by
- * {@link onMotionEvent}. Since motion events will be sent, motion up or cancel can still be
- * sent to cancel overview regardless the current state of launcher (eg. if overview is already
- * visible, this event will still be sent if user swipes up). When this signal is sent,
- * navigation bar will not handle any gestures such as quick scrub and the home button will
- * cancel (long) press.
- *
- * @deprecated
- */
- void onQuickStep(in MotionEvent event) = 9;
-
- /**
* Sent when there was an action on one of the onboarding tips view.
+ * TODO: Move this implementation to SystemUI completely
*/
void onTip(int actionType, int viewType) = 10;
@@ -125,6 +60,7 @@
/**
* Sent when back is triggered.
+ * TODO: Move this implementation to SystemUI completely
*/
void onBackAction(boolean completed, int downX, int downY, boolean isButton,
boolean gestureSwipeLeft) = 15;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 1369350..5a78c90 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -86,6 +86,8 @@
// enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble
// stack.
public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14;
+ // The global actions dialog is showing
+ public static final int SYSUI_STATE_GLOBAL_ACTIONS_SHOWING = 1 << 15;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -102,7 +104,8 @@
SYSUI_STATE_SEARCH_DISABLED,
SYSUI_STATE_TRACING_ENABLED,
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
- SYSUI_STATE_BUBBLES_EXPANDED
+ SYSUI_STATE_BUBBLES_EXPANDED,
+ SYSUI_STATE_GLOBAL_ACTIONS_SHOWING
})
public @interface SystemUiStateFlags {}
@@ -119,6 +122,7 @@
str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0
? "keygrd_occluded" : "");
str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : "");
+ str.add((flags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0 ? "global_actions" : "");
str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
@@ -192,8 +196,9 @@
* disabled.
*/
public static boolean isBackGestureDisabled(int sysuiStateFlags) {
- // Always allow when the bouncer is showing (even on top of the keyguard)
- if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0) {
+ // Always allow when the bouncer/global actions is showing (even on top of the keyguard)
+ if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0
+ || (sysuiStateFlags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0) {
return false;
}
// Disable when in immersive, or the notifications are interactive
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
index 8bd7c79..30156a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
@@ -58,7 +58,7 @@
*/
public void onReceive(Context context, Bundle bundle, View view, Size viewSize) {
if (mSurfaceControlViewHost != null) {
- mSurfaceControlViewHost.die();
+ mSurfaceControlViewHost.release();
}
SurfaceControl surfaceControl = SurfaceViewRequestUtils.getSurfaceControl(bundle);
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 0106609..b1e1434 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -19,8 +19,6 @@
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static android.telephony.PhoneStateListener.LISTEN_NONE;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
-
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -47,6 +45,7 @@
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -61,9 +60,11 @@
private final boolean mIsEmergencyCallCapable;
private final Handler mMainHandler;
+ private final Handler mBgHandler;
private boolean mTelephonyCapable;
private boolean mShowMissingSim;
private boolean mShowAirplaneMode;
+ private final AtomicBoolean mNetworkSupported = new AtomicBoolean();
@VisibleForTesting
protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private WifiManager mWifiManager;
@@ -78,12 +79,14 @@
new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedWakingUp() {
- if (mCarrierTextCallback != null) mCarrierTextCallback.finishedWakingUp();
+ final CarrierTextCallback callback = mCarrierTextCallback;
+ if (callback != null) callback.finishedWakingUp();
}
@Override
public void onStartedGoingToSleep() {
- if (mCarrierTextCallback != null) mCarrierTextCallback.startedGoingToSleep();
+ final CarrierTextCallback callback = mCarrierTextCallback;
+ if (callback != null) callback.startedGoingToSleep();
}
};
@@ -131,7 +134,7 @@
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveMobileDataSubscription = subId;
- if (mKeyguardUpdateMonitor != null) {
+ if (mNetworkSupported.get() && mCarrierTextCallback != null) {
updateCarrierText();
}
}
@@ -173,6 +176,17 @@
mSimSlotsNumber = getTelephonyManager().getSupportedModemCount();
mSimErrorState = new boolean[mSimSlotsNumber];
mMainHandler = Dependency.get(Dependency.MAIN_HANDLER);
+ mBgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
+ mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
+ mBgHandler.post(() -> {
+ boolean supported = ConnectivityManager.from(mContext).isNetworkSupported(
+ ConnectivityManager.TYPE_MOBILE);
+ if (supported && mNetworkSupported.compareAndSet(false, supported)) {
+ // This will set/remove the listeners appropriately. Note that it will never double
+ // add the listeners.
+ handleSetListening(mCarrierTextCallback);
+ }
+ });
}
private TelephonyManager getTelephonyManager() {
@@ -221,48 +235,51 @@
}
/**
- * Sets the listening status of this controller. If the callback is null, it is set to
- * not listening
+ * This may be called internally after retrieving the correct value of {@code mNetworkSupported}
+ * (assumed false to start). In that case, the following happens:
+ * <ul>
+ * <li> If there was a registered callback, and the network is supported, it will register
+ * listeners.
+ * <li> If there was not a registered callback, it will try to remove unregistered listeners
+ * which is a no-op
+ * </ul>
*
- * @param callback Callback to provide text updates
+ * This call will always be processed in a background thread.
*/
- public void setListening(CarrierTextCallback callback) {
+ private void handleSetListening(CarrierTextCallback callback) {
TelephonyManager telephonyManager = getTelephonyManager();
if (callback != null) {
mCarrierTextCallback = callback;
- // TODO(b/140034799)
- if (whitelistIpcs(() -> ConnectivityManager.from(mContext).isNetworkSupported(
- ConnectivityManager.TYPE_MOBILE))) {
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
+ if (mNetworkSupported.get()) {
// Keyguard update monitor expects callbacks from main thread
- mMainHandler.post(() -> {
- if (mKeyguardUpdateMonitor != null) {
- mKeyguardUpdateMonitor.registerCallback(mCallback);
- }
- });
+ mMainHandler.post(() -> mKeyguardUpdateMonitor.registerCallback(mCallback));
mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
telephonyManager.listen(mPhoneStateListener,
LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
} else {
// Don't listen and clear out the text when the device isn't a phone.
- mKeyguardUpdateMonitor = null;
- callback.updateCarrierInfo(new CarrierTextCallbackInfo("", null, false, null));
+ mMainHandler.post(() -> callback.updateCarrierInfo(
+ new CarrierTextCallbackInfo("", null, false, null)
+ ));
}
} else {
mCarrierTextCallback = null;
- if (mKeyguardUpdateMonitor != null) {
- // Keyguard update monitor expects callbacks from main thread
- mMainHandler.post(() -> {
- if (mKeyguardUpdateMonitor != null) {
- mKeyguardUpdateMonitor.removeCallback(mCallback);
- }
- });
- mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
- }
+ mMainHandler.post(() -> mKeyguardUpdateMonitor.removeCallback(mCallback));
+ mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
telephonyManager.listen(mPhoneStateListener, LISTEN_NONE);
}
}
+ /**
+ * Sets the listening status of this controller. If the callback is null, it is set to
+ * not listening.
+ *
+ * @param callback Callback to provide text updates
+ */
+ public void setListening(CarrierTextCallback callback) {
+ mBgHandler.post(() -> handleSetListening(callback));
+ }
+
protected List<SubscriptionInfo> getSubscriptionInfo() {
return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
}
@@ -500,7 +517,7 @@
*/
private CarrierTextController.StatusMode getStatusForIccState(int simState) {
final boolean missingAndNotProvisioned =
- !Dependency.get(KeyguardUpdateMonitor.class).isDeviceProvisioned()
+ !mKeyguardUpdateMonitor.isDeviceProvisioned()
&& (simState == TelephonyManager.SIM_STATE_ABSENT
|| simState == TelephonyManager.SIM_STATE_PERM_DISABLED);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt
deleted file mode 100644
index 487c295..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt
+++ /dev/null
@@ -1,33 +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.keyguard
-
-import android.graphics.drawable.Drawable
-
-import java.util.List
-
-/** State for lock screen media controls. */
-data class KeyguardMedia(
- val foregroundColor: Int,
- val backgroundColor: Int,
- val app: String?,
- val appIcon: Drawable?,
- val artist: String?,
- val song: String?,
- val artwork: Drawable?,
- val actionIcons: List<Drawable>
-)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
deleted file mode 100644
index af5196f..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
+++ /dev/null
@@ -1,381 +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.keyguard;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.Observer;
-import androidx.palette.graphics.Palette;
-
-import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.media.MediaControllerFactory;
-import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.stack.MediaHeaderView;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Media controls to display on the lockscreen
- *
- * TODO: Should extend MediaControlPanel to avoid code duplication.
- * Unfortunately, it isn't currently possible because the ActivatableNotificationView background is
- * different.
- */
-@Singleton
-public class KeyguardMediaPlayer {
-
- private static final String TAG = "KeyguardMediaPlayer";
- // Buttons that can be displayed on lock screen media controls.
- private static final int[] ACTION_IDS = {R.id.action0, R.id.action1, R.id.action2};
-
- private final Context mContext;
- private final Executor mBackgroundExecutor;
- private final KeyguardMediaViewModel mViewModel;
- private KeyguardMediaObserver mObserver;
-
- @Inject
- public KeyguardMediaPlayer(Context context, MediaControllerFactory factory,
- @Background Executor backgroundExecutor) {
- mContext = context;
- mBackgroundExecutor = backgroundExecutor;
- mViewModel = new KeyguardMediaViewModel(context, factory);
- }
-
- /** Binds media controls to a view hierarchy. */
- public void bindView(View v) {
- if (mObserver != null) {
- throw new IllegalStateException("cannot bind views, already bound");
- }
- mViewModel.loadDimens();
- mObserver = new KeyguardMediaObserver(v);
- // Control buttons
- for (int i = 0; i < ACTION_IDS.length; i++) {
- ImageButton button = v.findViewById(ACTION_IDS[i]);
- if (button == null) {
- continue;
- }
- final int index = i;
- button.setOnClickListener(unused -> mViewModel.onActionClick(index));
- }
- mViewModel.getKeyguardMedia().observeForever(mObserver);
- }
-
- /** Unbinds media controls. */
- public void unbindView() {
- if (mObserver == null) {
- throw new IllegalStateException("cannot unbind views, nothing bound");
- }
- mViewModel.getKeyguardMedia().removeObserver(mObserver);
- mObserver = null;
- }
-
- /** Clear the media controls because there isn't an active session. */
- public void clearControls() {
- mBackgroundExecutor.execute(mViewModel::clearControls);
- }
-
- /**
- * Update the media player
- *
- * TODO: consider registering a MediaLister instead of exposing this update method.
- *
- * @param entry Media notification that will be used to update the player
- * @param appIcon Icon for the app playing the media
- * @param mediaMetadata Media metadata that will be used to update the player
- */
- public void updateControls(NotificationEntry entry, Icon appIcon,
- MediaMetadata mediaMetadata) {
- if (mObserver == null) {
- throw new IllegalStateException("cannot update controls, views not bound");
- }
- if (mediaMetadata == null) {
- Log.d(TAG, "media metadata was null, closing media controls");
- // Note that clearControls() executes on the same background executor, so there
- // shouldn't be an issue with an outdated update running after clear. However, if stale
- // controls are observed then consider removing any enqueued updates.
- clearControls();
- return;
- }
- mBackgroundExecutor.execute(() -> mViewModel.updateControls(entry, appIcon, mediaMetadata));
- }
-
- /** ViewModel for KeyguardMediaControls. */
- private static final class KeyguardMediaViewModel {
-
- private final Context mContext;
- private final MediaControllerFactory mMediaControllerFactory;
- private final MutableLiveData<KeyguardMedia> mMedia = new MutableLiveData<>();
- private final Object mActionsLock = new Object();
- private List<PendingIntent> mActions;
- private float mAlbumArtRadius;
- private int mAlbumArtSize;
-
- KeyguardMediaViewModel(Context context, MediaControllerFactory factory) {
- mContext = context;
- mMediaControllerFactory = factory;
- loadDimens();
- }
-
- /** Close the media player because there isn't an active session. */
- public void clearControls() {
- synchronized (mActionsLock) {
- mActions = null;
- }
- mMedia.postValue(null);
- }
-
- /** Update the media player with information about the active session. */
- public void updateControls(NotificationEntry entry, Icon appIcon,
- MediaMetadata mediaMetadata) {
-
- // Check the playback state of the media controller. If it is null, then the session was
- // probably destroyed. Don't update in this case.
- final MediaSession.Token token = entry.getSbn().getNotification().extras
- .getParcelable(Notification.EXTRA_MEDIA_SESSION);
- final MediaController controller = token != null
- ? mMediaControllerFactory.create(token) : null;
- if (controller != null && controller.getPlaybackState() == null) {
- clearControls();
- return;
- }
-
- // Foreground and Background colors computed from album art
- Notification notif = entry.getSbn().getNotification();
- int fgColor = notif.color;
- int bgColor = entry.getRow() == null ? -1 : entry.getRow().getCurrentBackgroundTint();
- Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
- if (artworkBitmap == null) {
- artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- }
- if (artworkBitmap != null) {
- // If we have art, get colors from that
- Palette p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
- .generate();
- Palette.Swatch swatch = MediaNotificationProcessor.findBackgroundSwatch(p);
- bgColor = swatch.getRgb();
- fgColor = MediaNotificationProcessor.selectForegroundColor(bgColor, p);
- }
- // Make sure colors will be legible
- boolean isDark = !ContrastColorUtil.isColorLight(bgColor);
- fgColor = ContrastColorUtil.resolveContrastColor(mContext, fgColor, bgColor,
- isDark);
- fgColor = ContrastColorUtil.ensureTextContrast(fgColor, bgColor, isDark);
-
- // Album art
- RoundedBitmapDrawable artwork = null;
- if (artworkBitmap != null) {
- Bitmap original = artworkBitmap.copy(Bitmap.Config.ARGB_8888, true);
- Bitmap scaled = Bitmap.createScaledBitmap(original, mAlbumArtSize, mAlbumArtSize,
- false);
- artwork = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
- artwork.setCornerRadius(mAlbumArtRadius);
- }
-
- // App name
- Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif);
- String app = builder.loadHeaderAppName();
-
- // App Icon
- Drawable appIconDrawable = appIcon.loadDrawable(mContext);
-
- // Song name
- String song = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
-
- // Artist name
- String artist = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
-
- // Control buttons
- List<Drawable> actionIcons = new ArrayList<>();
- final List<PendingIntent> intents = new ArrayList<>();
- Notification.Action[] actions = notif.actions;
- final int[] actionsToShow = notif.extras.getIntArray(
- Notification.EXTRA_COMPACT_ACTIONS);
-
- Context packageContext = entry.getSbn().getPackageContext(mContext);
- for (int i = 0; i < ACTION_IDS.length; i++) {
- if (actionsToShow != null && actions != null && i < actionsToShow.length
- && actionsToShow[i] < actions.length) {
- final int idx = actionsToShow[i];
- actionIcons.add(actions[idx].getIcon().loadDrawable(packageContext));
- intents.add(actions[idx].actionIntent);
- } else {
- actionIcons.add(null);
- intents.add(null);
- }
- }
- synchronized (mActionsLock) {
- mActions = intents;
- }
-
- KeyguardMedia data = new KeyguardMedia(fgColor, bgColor, app, appIconDrawable, artist,
- song, artwork, actionIcons);
- mMedia.postValue(data);
- }
-
- /** Gets state for the lock screen media controls. */
- public LiveData<KeyguardMedia> getKeyguardMedia() {
- return mMedia;
- }
-
- /**
- * Handle user clicks on media control buttons (actions).
- *
- * @param index position of the button that was clicked.
- */
- public void onActionClick(int index) {
- PendingIntent intent = null;
- // This might block the ui thread to wait for the lock. Currently, however, the
- // lock is held by the bg thread to assign a member, which should be fast. An
- // alternative could be to add the intents to the state and let the observer set
- // the onClick listeners.
- synchronized (mActionsLock) {
- if (mActions != null && index < mActions.size()) {
- intent = mActions.get(index);
- }
- }
- if (intent != null) {
- try {
- intent.send();
- } catch (PendingIntent.CanceledException e) {
- Log.d(TAG, "failed to send action intent", e);
- }
- }
- }
-
- void loadDimens() {
- mAlbumArtRadius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
- mAlbumArtSize = (int) mContext.getResources().getDimension(
- R.dimen.qs_media_album_size);
- }
- }
-
- /** Observer for state changes of lock screen media controls. */
- private static final class KeyguardMediaObserver implements Observer<KeyguardMedia> {
-
- private final View mRootView;
- private final MediaHeaderView mMediaHeaderView;
- private final ImageView mAlbumView;
- private final ImageView mAppIconView;
- private final TextView mAppNameView;
- private final TextView mTitleView;
- private final TextView mArtistView;
- private final List<ImageButton> mButtonViews = new ArrayList<>();
-
- KeyguardMediaObserver(View v) {
- mRootView = v;
- mMediaHeaderView = v instanceof MediaHeaderView ? (MediaHeaderView) v : null;
- mAlbumView = v.findViewById(R.id.album_art);
- mAppIconView = v.findViewById(R.id.icon);
- mAppNameView = v.findViewById(R.id.app_name);
- mTitleView = v.findViewById(R.id.header_title);
- mArtistView = v.findViewById(R.id.header_artist);
- for (int i = 0; i < ACTION_IDS.length; i++) {
- mButtonViews.add(v.findViewById(ACTION_IDS[i]));
- }
- }
-
- /** Updates lock screen media player views when state changes. */
- @Override
- public void onChanged(KeyguardMedia data) {
- if (data == null) {
- mRootView.setVisibility(View.GONE);
- return;
- }
- mRootView.setVisibility(View.VISIBLE);
-
- // Background color
- if (mMediaHeaderView != null) {
- mMediaHeaderView.setBackgroundColor(data.getBackgroundColor());
- }
-
- // Album art
- if (mAlbumView != null) {
- mAlbumView.setImageDrawable(data.getArtwork());
- mAlbumView.setVisibility(data.getArtwork() == null ? View.GONE : View.VISIBLE);
- }
-
- // App icon
- if (mAppIconView != null) {
- Drawable iconDrawable = data.getAppIcon();
- iconDrawable.setTint(data.getForegroundColor());
- mAppIconView.setImageDrawable(iconDrawable);
- }
-
- // App name
- if (mAppNameView != null) {
- String appNameString = data.getApp();
- mAppNameView.setText(appNameString);
- mAppNameView.setTextColor(data.getForegroundColor());
- }
-
- // Song name
- if (mTitleView != null) {
- mTitleView.setText(data.getSong());
- mTitleView.setTextColor(data.getForegroundColor());
- }
-
- // Artist name
- if (mArtistView != null) {
- mArtistView.setText(data.getArtist());
- mArtistView.setTextColor(data.getForegroundColor());
- }
-
- // Control buttons
- for (int i = 0; i < ACTION_IDS.length; i++) {
- ImageButton button = mButtonViews.get(i);
- if (button == null) {
- continue;
- }
- Drawable icon = data.getActionIcons().get(i);
- if (icon == null) {
- button.setVisibility(View.GONE);
- button.setImageDrawable(null);
- } else {
- button.setVisibility(View.VISIBLE);
- button.setImageDrawable(icon);
- button.setImageTintList(ColorStateList.valueOf(data.getForegroundColor()));
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b99fb05..1a4dd1e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -103,7 +103,8 @@
private KeyguardSecurityModel mSecurityModel;
private LockPatternUtils mLockPatternUtils;
- private KeyguardSecurityViewFlipper mSecurityViewFlipper;
+ @VisibleForTesting
+ KeyguardSecurityViewFlipper mSecurityViewFlipper;
private boolean mIsVerifyUnlockOnly;
private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
private KeyguardSecurityView mCurrentSecurityView;
@@ -375,6 +376,9 @@
}
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
+ if (mCurrentSecuritySelection == SecurityMode.Password) {
+ mSecurityViewFlipper.getWindowInsetsController().hide(WindowInsets.Type.ime());
+ }
if (mCurrentSecuritySelection != SecurityMode.None) {
return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
onFinishRunnable);
@@ -397,7 +401,8 @@
return mSecurityViewFlipper.getTitle();
}
- private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
+ @VisibleForTesting
+ protected KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
KeyguardSecurityView view = null;
final int children = mSecurityViewFlipper.getChildCount();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a96ef91..0db713e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -33,6 +33,7 @@
import android.annotation.AnyThread;
import android.annotation.MainThread;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
@@ -94,8 +95,10 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.Assert;
import com.android.systemui.util.RingerModeTracker;
@@ -219,6 +222,7 @@
private final Context mContext;
private final boolean mIsPrimaryUser;
+ private final StatusBarStateController mStatusBarStateController;
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
@@ -244,8 +248,7 @@
// Battery status
private BatteryStatus mBatteryStatus;
- @VisibleForTesting
- protected StrongAuthTracker mStrongAuthTracker;
+ private StrongAuthTracker mStrongAuthTracker;
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
@@ -1509,6 +1512,16 @@
mUserTrustIsUsuallyManaged.delete(userId);
}
+ @VisibleForTesting
+ protected void setStrongAuthTracker(@NonNull StrongAuthTracker tracker) {
+ if (mStrongAuthTracker != null) {
+ mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker);
+ }
+
+ mStrongAuthTracker = tracker;
+ mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
+ }
+
private void registerRingerTracker() {
mRingerModeTracker.getRingerMode().observeForever(mRingerModeObserver);
}
@@ -1521,7 +1534,9 @@
BroadcastDispatcher broadcastDispatcher,
DumpManager dumpManager,
RingerModeTracker ringerModeTracker,
- @Background Executor backgroundExecutor) {
+ @Background Executor backgroundExecutor,
+ StatusBarStateController statusBarStateController,
+ LockPatternUtils lockPatternUtils) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
@@ -1529,6 +1544,8 @@
mBackgroundExecutor = backgroundExecutor;
mBroadcastDispatcher = broadcastDispatcher;
mRingerModeTracker = ringerModeTracker;
+ mStatusBarStateController = statusBarStateController;
+ mLockPatternUtils = lockPatternUtils;
dumpManager.registerDumpable(getClass().getName(), this);
mHandler = new Handler(mainLooper) {
@@ -1664,6 +1681,15 @@
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler);
+ // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the
+ // listener now with the service state from the default sub.
+ mBackgroundExecutor.execute(() -> {
+ int subId = SubscriptionManager.getDefaultSubscriptionId();
+ ServiceState serviceState = mContext.getSystemService(TelephonyManager.class)
+ .getServiceStateForSubscriber(subId);
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
+ });
mHandler.post(this::registerRingerTracker);
@@ -1688,8 +1714,8 @@
mTrustManager = context.getSystemService(TrustManager.class);
mTrustManager.registerTrustListener(this);
- mLockPatternUtils = new LockPatternUtils(context);
- mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
+
+ setStrongAuthTracker(mStrongAuthTracker);
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
@@ -1846,8 +1872,7 @@
boolean shouldListenForFace = shouldListenForFace();
if (mFaceRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFace) {
stopListeningForFace();
- } else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING
- && shouldListenForFace) {
+ } else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
startListeningForFace();
}
}
@@ -1885,7 +1910,10 @@
* If face auth is allows to scan on this exact moment.
*/
public boolean shouldListenForFace() {
- final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep;
+ final boolean statusBarShadeLocked =
+ mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED;
+ final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
+ && !statusBarShadeLocked;
final int user = getCurrentUser();
final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
final boolean isLockDown =
@@ -2831,6 +2859,9 @@
mBroadcastDispatcher.unregisterReceiver(mBroadcastAllReceiver);
mRingerModeTracker.getRingerMode().removeObserver(mRingerModeObserver);
+ mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker);
+ mTrustManager.unregisterTrustListener(this);
+
mHandler.removeCallbacksAndMessages(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
index 284074e..3015710 100644
--- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -37,20 +37,22 @@
private val cameraManager: CameraManager,
private val cutoutProtectionPath: Path,
private val targetCameraId: String,
+ excludedPackages: String,
private val executor: Executor
) {
private var cutoutBounds = Rect()
+ private val excludedPackageIds: Set<String>
private val listeners = mutableListOf<CameraTransitionCallback>()
private val availabilityCallback: CameraManager.AvailabilityCallback =
object : CameraManager.AvailabilityCallback() {
- override fun onCameraAvailable(cameraId: String) {
+ override fun onCameraClosed(cameraId: String) {
if (targetCameraId == cameraId) {
notifyCameraInactive()
}
}
- override fun onCameraUnavailable(cameraId: String) {
- if (targetCameraId == cameraId) {
+ override fun onCameraOpened(cameraId: String, packageId: String) {
+ if (targetCameraId == cameraId && !isExcluded(packageId)) {
notifyCameraActive()
}
}
@@ -64,6 +66,7 @@
computed.top.roundToInt(),
computed.right.roundToInt(),
computed.bottom.roundToInt())
+ excludedPackageIds = excludedPackages.split(",").toSet()
}
/**
@@ -87,6 +90,10 @@
listeners.remove(callback)
}
+ private fun isExcluded(packageId: String): Boolean {
+ return excludedPackageIds.contains(packageId)
+ }
+
private fun registerCameraListener() {
cameraManager.registerAvailabilityCallback(executor, availabilityCallback)
}
@@ -118,9 +125,10 @@
val res = context.resources
val pathString = res.getString(R.string.config_frontBuiltInDisplayCutoutProtection)
val cameraId = res.getString(R.string.config_protectedCameraId)
+ val excluded = res.getString(R.string.config_cameraProtectionExcludedPackages)
return CameraAvailabilityListener(
- manager, pathFromString(pathString), cameraId, executor)
+ manager, pathFromString(pathString), cameraId, excluded, executor)
}
private fun pathFromString(pathString: String): Path {
@@ -135,4 +143,4 @@
return p
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index b727563..0135e4c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -128,6 +128,8 @@
public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT =
AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT; // 13
+ private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
private Recents mRecents;
private StatusBar mStatusBar;
private SystemActionsBroadcastReceiver mReceiver;
@@ -147,7 +149,11 @@
@Override
public void start() {
- mContext.registerReceiverForAllUsers(mReceiver, mReceiver.createIntentFilter(), null, null);
+ mContext.registerReceiverForAllUsers(
+ mReceiver,
+ mReceiver.createIntentFilter(),
+ PERMISSION_SELF,
+ null);
registerActions();
}
@@ -397,6 +403,7 @@
case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER:
case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: {
Intent intent = new Intent(intentAction);
+ intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
default:
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 8cd89dd..525e989 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Log;
import android.view.accessibility.AccessibilityManager;
@@ -61,6 +62,7 @@
private static final long DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS = 0;
private static final long DEFAULT_SHOW_AND_GO_DURATION_MS = TimeUnit.SECONDS.toMillis(3);
+ private static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
/**
* This is the default behavior that will be used once the system is up. It will be set once the
@@ -203,6 +205,10 @@
}
private boolean handlesUnblocked(boolean ignoreThreshold) {
+ if (!isUserSetupComplete()) {
+ return false;
+ }
+
long timeSinceHidden = SystemClock.elapsedRealtime() - mHandlesLastHiddenAt;
boolean notThrottled = ignoreThreshold || timeSinceHidden >= getShownFrequencyThreshold();
ComponentName assistantComponent =
@@ -284,6 +290,11 @@
mShowAndGoEndsAt = 0;
}
+ private boolean isUserSetupComplete() {
+ return Settings.Secure.getInt(
+ mContext.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+ }
+
@VisibleForTesting
void setInGesturalModeForTest(boolean inGesturalMode) {
mInGesturalMode = inGesturalMode;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 7dea7f8..7c25d28 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -432,7 +432,7 @@
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
}
- public void updateState(@BiometricState int newState) {
+ void updateState(@BiometricState int newState) {
Log.v(TAG, "newState: " + newState);
switch (newState) {
@@ -453,8 +453,10 @@
}
announceForAccessibility(getResources()
.getString(R.string.biometric_dialog_authenticated));
- mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED),
- getDelayAfterAuthenticatedDurationMs());
+ mHandler.postDelayed(() -> {
+ Log.d(TAG, "Sending ACTION_AUTHENTICATED");
+ mCallback.onAction(Callback.ACTION_AUTHENTICATED);
+ }, getDelayAfterAuthenticatedDurationMs());
break;
case STATE_PENDING_CONFIRMATION:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b736b4d..1dd6409 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -34,7 +34,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowInsets.Type;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -113,6 +112,7 @@
int mModalityMask;
boolean mSkipIntro;
long mOperationId;
+ int mSysUiSessionId;
}
public static class Builder {
@@ -158,6 +158,11 @@
return this;
}
+ public Builder setSysUiSessionId(int sysUiSessionId) {
+ mConfig.mSysUiSessionId = sysUiSessionId;
+ return this;
+ }
+
public AuthContainerView build(int modalityMask) {
mConfig.mModalityMask = modalityMask;
return new AuthContainerView(mConfig, new Injector());
@@ -203,6 +208,9 @@
final class BiometricCallback implements AuthBiometricView.Callback {
@Override
public void onAction(int action) {
+ Log.d(TAG, "onAction: " + action
+ + ", sysUiSessionId: " + mConfig.mSysUiSessionId
+ + ", state: " + mContainerState);
switch (action) {
case AuthBiometricView.Callback.ACTION_AUTHENTICATED:
animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
@@ -300,6 +308,7 @@
return true;
});
+ setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
setFocusableInTouchMode(true);
requestFocus();
}
@@ -461,13 +470,13 @@
if (animate) {
animateAway(false /* sendReason */, 0 /* reason */);
} else {
- removeWindowIfAttached();
+ removeWindowIfAttached(false /* sendReason */);
}
}
@Override
public void dismissFromSystemServer() {
- removeWindowIfAttached();
+ removeWindowIfAttached(true /* sendReason */);
}
@Override
@@ -540,7 +549,7 @@
final Runnable endActionRunnable = () -> {
setVisibility(View.INVISIBLE);
- removeWindowIfAttached();
+ removeWindowIfAttached(true /* sendReason */);
};
postOnAnimation(() -> {
@@ -575,19 +584,24 @@
}
private void sendPendingCallbackIfNotNull() {
- Log.d(TAG, "pendingCallback: " + mPendingCallbackReason);
+ Log.d(TAG, "pendingCallback: " + mPendingCallbackReason
+ + " sysUISessionId: " + mConfig.mSysUiSessionId);
if (mPendingCallbackReason != null) {
mConfig.mCallback.onDismissed(mPendingCallbackReason, mCredentialAttestation);
mPendingCallbackReason = null;
}
}
- private void removeWindowIfAttached() {
- sendPendingCallbackIfNotNull();
+ private void removeWindowIfAttached(boolean sendReason) {
+ if (sendReason) {
+ sendPendingCallbackIfNotNull();
+ }
if (mContainerState == STATE_GONE) {
+ Log.w(TAG, "Container already STATE_GONE, mSysUiSessionId: " + mConfig.mSysUiSessionId);
return;
}
+ Log.d(TAG, "Removing container, mSysUiSessionId: " + mConfig.mSysUiSessionId);
mContainerState = STATE_GONE;
mWindowManager.removeView(this);
}
@@ -620,7 +634,6 @@
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("BiometricPrompt");
lp.token = windowToken;
- lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~Type.statusBars());
return lp;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 0c6794c..9f0ea3e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -276,14 +276,15 @@
@Override
public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, int sysUiSessionId) {
final int authenticators = Utils.getAuthenticators(bundle);
if (DEBUG) {
Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators
+ ", biometricModality: " + biometricModality
+ ", requireConfirmation: " + requireConfirmation
- + ", operationId: " + operationId);
+ + ", operationId: " + operationId
+ + ", sysUiSessionId: " + sysUiSessionId);
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -293,6 +294,7 @@
args.argi2 = userId;
args.arg4 = opPackageName;
args.arg5 = operationId;
+ args.argi3 = sysUiSessionId;
boolean skipAnimation = false;
if (mCurrentDialog != null) {
@@ -382,6 +384,7 @@
final int userId = args.argi2;
final String opPackageName = (String) args.arg4;
final long operationId = (long) args.arg5;
+ final int sysUiSessionId = args.argi3;
// Create a new dialog but do not replace the current one yet.
final AuthDialog newDialog = buildDialog(
@@ -391,7 +394,8 @@
type,
opPackageName,
skipAnimation,
- operationId);
+ operationId,
+ sysUiSessionId);
if (newDialog == null) {
Log.e(TAG, "Unsupported type: " + type);
@@ -403,7 +407,8 @@
+ " savedState: " + savedState
+ " mCurrentDialog: " + mCurrentDialog
+ " newDialog: " + newDialog
- + " type: " + type);
+ + " type: " + type
+ + " sysUiSessionId: " + sysUiSessionId);
}
if (mCurrentDialog != null) {
@@ -458,7 +463,8 @@
}
protected AuthDialog buildDialog(Bundle biometricPromptBundle, boolean requireConfirmation,
- int userId, int type, String opPackageName, boolean skipIntro, long operationId) {
+ int userId, int type, String opPackageName, boolean skipIntro, long operationId,
+ int sysUiSessionId) {
return new AuthContainerView.Builder(mContext)
.setCallback(this)
.setBiometricPromptBundle(biometricPromptBundle)
@@ -467,6 +473,7 @@
.setOpPackageName(opPackageName)
.setSkipIntro(skipIntro)
.setOperationId(operationId)
+ .setSysUiSessionId(sysUiSessionId)
.build(type);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index 4e84f06..3272fb7 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -32,6 +32,8 @@
import com.android.systemui.Dumpable
import java.io.FileDescriptor
import java.io.PrintWriter
+import java.lang.IllegalArgumentException
+import java.lang.IllegalStateException
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
@@ -211,7 +213,12 @@
*/
override fun run() {
if (registered.get()) {
- context.unregisterReceiver(this@UserBroadcastDispatcher)
+ try {
+ context.unregisterReceiver(this@UserBroadcastDispatcher)
+ } catch (e: IllegalArgumentException) {
+ Log.e(TAG, "Trying to unregister unregistered receiver for user $userId",
+ IllegalStateException(e))
+ }
registered.set(false)
}
// Short interval without receiver, this can be problematic
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 0dbee66..f1b401e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -102,6 +102,13 @@
return user.getIdentifier() + "|" + entry.getSbn().getPackageName();
}
+ // TODO: Decouple Bubble from NotificationEntry and transform ShortcutInfo into Bubble
+ Bubble(ShortcutInfo shortcutInfo) {
+ mShortcutInfo = shortcutInfo;
+ mKey = shortcutInfo.getId();
+ mGroupId = shortcutInfo.getId();
+ }
+
/** Used in tests when no UI is required. */
@VisibleForTesting(visibility = PRIVATE)
Bubble(NotificationEntry e,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index ad8d57b..a578f33 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -175,7 +175,7 @@
private INotificationManager mINotificationManager;
// Callback that updates BubbleOverflowActivity on data change.
- @Nullable private BubbleData.Listener mOverflowListener = null;
+ @Nullable private Runnable mOverflowCallback = null;
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private IStatusBarService mBarService;
@@ -198,6 +198,11 @@
/** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
+ /**
+ * Last known screen density, used to detect display size changes in {@link #onConfigChanged}.
+ */
+ private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED;
+
private boolean mInflateSynchronously;
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
@@ -280,31 +285,6 @@
}
}
- public BubbleController(Context context,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
- ShadeController shadeController,
- BubbleData data,
- ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController,
- NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManager groupManager,
- NotificationEntryManager entryManager,
- NotifPipeline notifPipeline,
- FeatureFlags featureFlags,
- DumpManager dumpManager,
- FloatingContentCoordinator floatingContentCoordinator,
- BubbleDataRepository dataRepository,
- SysUiState sysUiState,
- INotificationManager notificationManager) {
- this(context, notificationShadeWindowController, statusBarStateController, shadeController,
- data, null /* synchronizer */, configurationController, interruptionStateProvider,
- zenModeController, notifUserManager, groupManager, entryManager,
- notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
- dataRepository, sysUiState, notificationManager);
- }
-
/**
* Injected constructor. See {@link BubbleModule}.
*/
@@ -326,7 +306,8 @@
FloatingContentCoordinator floatingContentCoordinator,
BubbleDataRepository dataRepository,
SysUiState sysUiState,
- INotificationManager notificationManager) {
+ INotificationManager notificationManager,
+ WindowManager windowManager) {
dumpManager.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
@@ -395,7 +376,7 @@
}
mSurfaceSynchronizer = synchronizer;
- mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ mWindowManager = windowManager;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -595,8 +576,8 @@
mInflateSynchronously = inflateSynchronously;
}
- void setOverflowListener(BubbleData.Listener listener) {
- mOverflowListener = listener;
+ void setOverflowCallback(Runnable updateOverflow) {
+ mOverflowCallback = updateOverflow;
}
/**
@@ -634,7 +615,7 @@
// themselves.
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY,
// Start not focusable - we'll become focusable when expanded so the ActivityView
// can use the IME.
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -729,9 +710,16 @@
@Override
public void onConfigChanged(Configuration newConfig) {
- if (mStackView != null && newConfig != null && newConfig.orientation != mOrientation) {
- mOrientation = newConfig.orientation;
- mStackView.onOrientationChanged(newConfig.orientation);
+ if (mStackView != null && newConfig != null) {
+ if (newConfig.orientation != mOrientation) {
+ mOrientation = newConfig.orientation;
+ mStackView.onOrientationChanged(newConfig.orientation);
+ }
+ if (newConfig.densityDpi != mDensityDpi) {
+ mDensityDpi = newConfig.densityDpi;
+ mBubbleIconFactory = new BubbleIconFactory(mContext);
+ mStackView.onDisplaySizeChanged();
+ }
}
}
@@ -894,6 +882,7 @@
// Update the state in NotificationManagerService
try {
int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
mBarService.onNotificationBubbleChanged(entry.getKey(), shouldBubble, flags);
} catch (RemoteException e) {
}
@@ -1010,8 +999,8 @@
@Override
public void applyUpdate(BubbleData.Update update) {
// Update bubbles in overflow.
- if (mOverflowListener != null) {
- mOverflowListener.applyUpdate(update);
+ if (mOverflowCallback != null) {
+ mOverflowCallback.run();
}
// Collapsing? Do this first before remaining steps.
@@ -1039,8 +1028,7 @@
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
&& (!bubble.showInShade()
|| reason == DISMISS_NOTIF_CANCEL
- || reason == DISMISS_GROUP_CANCELLED
- || reason == DISMISS_OVERFLOW_MAX_REACHED)) {
+ || reason == DISMISS_GROUP_CANCELLED)) {
// The bubble is now gone & the notification is hidden from the shade, so
// time to actually remove it
for (NotifCallback cb : mCallbacks) {
@@ -1111,6 +1099,9 @@
Log.d(TAG, BubbleDebugConfig.formatBubblesString(mStackView.getBubblesOnScreen(),
mStackView.getExpandedBubble()));
}
+ Log.d(TAG, "\n[BubbleData] overflow:");
+ Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getOverflowBubbles(),
+ null) + "\n");
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index f2b1c03..65d5beb 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -74,8 +74,6 @@
@Nullable Bubble selectedBubble;
@Nullable Bubble addedBubble;
@Nullable Bubble updatedBubble;
- @Nullable Bubble addedOverflowBubble;
- @Nullable Bubble removedOverflowBubble;
// Pair with Bubble and @DismissReason Integer
final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>();
@@ -94,12 +92,10 @@
|| addedBubble != null
|| updatedBubble != null
|| !removedBubbles.isEmpty()
- || addedOverflowBubble != null
- || removedOverflowBubble != null
|| orderChanged;
}
- void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
+ void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
removedBubbles.add(new Pair<>(bubbleToRemove, reason));
}
}
@@ -237,7 +233,6 @@
private void moveOverflowBubbleToPending(Bubble b) {
mOverflowBubbles.remove(b);
- mStateChange.removedOverflowBubble = b;
mPendingBubbles.add(b);
}
@@ -445,9 +440,8 @@
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "Cancel overflow bubble: " + b);
}
- mOverflowBubbles.remove(b);
mStateChange.bubbleRemoved(b, reason);
- mStateChange.removedOverflowBubble = b;
+ mOverflowBubbles.remove(b);
}
return;
}
@@ -489,7 +483,6 @@
Log.d(TAG, "Overflowing: " + bubble);
}
mOverflowBubbles.add(0, bubble);
- mStateChange.addedOverflowBubble = bubble;
bubble.stopInflation();
if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
// Remove oldest bubble.
@@ -497,9 +490,8 @@
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "Overflow full. Remove: " + oldest);
}
- mOverflowBubbles.remove(oldest);
- mStateChange.removedOverflowBubble = oldest;
mStateChange.bubbleRemoved(oldest, BubbleController.DISMISS_OVERFLOW_MAX_REACHED);
+ mOverflowBubbles.remove(oldest);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index 63dd801..ba93f41 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -15,56 +15,68 @@
*/
package com.android.systemui.bubbles
+import android.annotation.SuppressLint
import android.annotation.UserIdInt
+import android.content.pm.LauncherApps
+import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
+import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED
+import android.os.UserHandle
+import android.util.Log
+import com.android.systemui.bubbles.storage.BubbleEntity
import com.android.systemui.bubbles.storage.BubblePersistentRepository
import com.android.systemui.bubbles.storage.BubbleVolatileRepository
-import com.android.systemui.bubbles.storage.BubbleXmlEntity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
+
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
internal class BubbleDataRepository @Inject constructor(
private val volatileRepository: BubbleVolatileRepository,
- private val persistentRepository: BubblePersistentRepository
+ private val persistentRepository: BubblePersistentRepository,
+ private val launcherApps: LauncherApps
) {
private val ioScope = CoroutineScope(Dispatchers.IO)
+ private val uiScope = CoroutineScope(Dispatchers.Main)
private var job: Job? = null
/**
* Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
* asynchronously.
*/
- fun addBubble(@UserIdInt userId: Int, bubble: Bubble) {
- volatileRepository.addBubble(
- BubbleXmlEntity(userId, bubble.packageName, bubble.shortcutInfo?.id ?: return))
- persistToDisk()
- }
+ fun addBubble(@UserIdInt userId: Int, bubble: Bubble) = addBubbles(userId, listOf(bubble))
/**
* Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
* asynchronously.
*/
fun addBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) {
- volatileRepository.addBubbles(bubbles.mapNotNull {
- val shortcutId = it.shortcutInfo?.id ?: return@mapNotNull null
- BubbleXmlEntity(userId, it.packageName, shortcutId)
- })
- persistToDisk()
+ if (DEBUG) Log.d(TAG, "adding ${bubbles.size} bubbles")
+ val entities = transform(userId, bubbles).also(volatileRepository::addBubbles)
+ if (entities.isNotEmpty()) persistToDisk()
}
+ /**
+ * Removes the bubbles from memory, then persists the snapshot to disk asynchronously.
+ */
fun removeBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) {
- volatileRepository.removeBubbles(bubbles.mapNotNull {
- val shortcutId = it.shortcutInfo?.id ?: return@mapNotNull null
- BubbleXmlEntity(userId, it.packageName, shortcutId)
- })
- persistToDisk()
+ if (DEBUG) Log.d(TAG, "removing ${bubbles.size} bubbles")
+ val entities = transform(userId, bubbles).also(volatileRepository::removeBubbles)
+ if (entities.isNotEmpty()) persistToDisk()
+ }
+
+ private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
+ return bubbles.mapNotNull { b ->
+ val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null
+ BubbleEntity(userId, b.packageName, shortcutId)
+ }
}
/**
@@ -92,4 +104,64 @@
persistentRepository.persistsToDisk(volatileRepository.bubbles)
}
}
+
+ /**
+ * Load bubbles from disk.
+ */
+ // TODO: call this method from BubbleController and update UI
+ @SuppressLint("WrongConstant")
+ fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
+ /**
+ * Load BubbleEntity from disk.
+ * e.g.
+ * [
+ * BubbleEntity(0, "com.example.messenger", "id-2"),
+ * BubbleEntity(10, "com.example.chat", "my-id1")
+ * BubbleEntity(0, "com.example.messenger", "id-1")
+ * ]
+ */
+ val entities = persistentRepository.readFromDisk()
+ volatileRepository.addBubbles(entities)
+ /**
+ * Extract userId/packageName from these entities.
+ * e.g.
+ * [
+ * ShortcutKey(0, "com.example.messenger"), ShortcutKey(0, "com.example.chat")
+ * ]
+ */
+ val shortcutKeys = entities.map { ShortcutKey(it.userId, it.packageName) }.toSet()
+ /**
+ * Retrieve shortcuts with given userId/packageName combination, then construct a mapping
+ * between BubbleEntity and ShortcutInfo.
+ * e.g.
+ * {
+ * BubbleEntity(0, "com.example.messenger", "id-0") ->
+ * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-0"),
+ * BubbleEntity(0, "com.example.messenger", "id-2") ->
+ * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-2"),
+ * BubbleEntity(10, "com.example.chat", "id-1") ->
+ * ShortcutInfo(userId=10, pkg="com.example.chat", id="id-1"),
+ * BubbleEntity(10, "com.example.chat", "id-3") ->
+ * ShortcutInfo(userId=10, pkg="com.example.chat", id="id-3")
+ * }
+ */
+ val shortcutMap = shortcutKeys.flatMap { key ->
+ launcherApps.getShortcuts(
+ LauncherApps.ShortcutQuery()
+ .setPackage(key.pkg)
+ .setQueryFlags(SHORTCUT_QUERY_FLAG), UserHandle.of(key.userId))
+ ?.map { BubbleEntity(key.userId, key.pkg, it.id) to it } ?: emptyList()
+ }.toMap()
+ // For each entity loaded from xml, find the corresponding ShortcutInfo then convert them
+ // into Bubble.
+ val bubbles = entities.mapNotNull { entity -> shortcutMap[entity]?.let { Bubble(it) } }
+ uiScope.launch { cb(bubbles) }
+ }
+
+ private data class ShortcutKey(val userId: Int, val pkg: String)
}
+
+private const val TAG = "BubbleDataRepository"
+private const val DEBUG = false
+private const val SHORTCUT_QUERY_FLAG =
+ FLAG_MATCH_DYNAMIC or FLAG_MATCH_PINNED_BY_ANY_LAUNCHER or FLAG_MATCH_CACHED
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index b3c2c6d..baf92dc 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -57,6 +57,7 @@
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.LinearLayout;
import com.android.internal.policy.ScreenDecorationsUtils;
@@ -456,6 +457,19 @@
mSettingsIcon.setContentDescription(getResources().getString(
R.string.bubbles_settings_button_description, bubble.getAppName()));
+ mSettingsIcon.setAccessibilityDelegate(
+ new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // On focus, have TalkBack say
+ // "Actions available. Use swipe up then right to view."
+ // in addition to the default "double tap to activate".
+ mStackView.setupLocalMenu(info);
+ }
+ });
+
if (isNew) {
mPendingIntent = mBubble.getBubbleIntent();
if (mPendingIntent != null || mBubble.getShortcutInfo() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index 13669a6..f4eb580 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -58,12 +58,13 @@
public BubbleOverflow(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
- mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
- mIconBitmapSize = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_overflow_icon_bitmap_size);
}
void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) {
+ mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
+ mIconBitmapSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.bubble_overflow_icon_bitmap_size);
+
mExpandedView = (BubbleExpandedView) mInflater.inflate(
R.layout.bubble_expanded_view, parentViewGroup /* root */,
false /* attachToRoot */);
@@ -73,12 +74,14 @@
updateIcon(mContext, parentViewGroup);
}
- // TODO(b/149146374) Propagate theme change to bubbles in overflow.
void updateIcon(Context context, ViewGroup parentViewGroup) {
+ mContext = context;
mInflater = LayoutInflater.from(context);
mOverflowBtn = (BadgedImageView) mInflater.inflate(R.layout.bubble_overflow_button,
parentViewGroup /* root */,
false /* attachToRoot */);
+ mOverflowBtn.setContentDescription(mContext.getResources().getString(
+ R.string.bubble_overflow_button_content_description));
TypedArray ta = mContext.obtainStyledAttributes(
new int[]{android.R.attr.colorBackgroundFloating});
@@ -86,7 +89,7 @@
ta.recycle();
TypedValue typedValue = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+ mContext.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
int colorAccent = mContext.getColor(typedValue.resourceId);
mOverflowBtn.getDrawable().setTint(colorAccent);
mDotColor = colorAccent;
@@ -96,7 +99,7 @@
mBitmapSize - mIconBitmapSize /* inset */);
AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(bg, fg);
- BubbleIconFactory iconFactory = new BubbleIconFactory(context);
+ BubbleIconFactory iconFactory = new BubbleIconFactory(mContext);
mIcon = iconFactory.createBadgedIconBitmap(adaptiveIconDrawable,
null /* user */,
true /* shrinkNonAdaptiveIcons */).icon;
@@ -105,7 +108,7 @@
null /* outBounds */, null /* path */, null /* outMaskShape */);
float radius = DEFAULT_PATH_SIZE / 2f;
mPath = PathParser.createPathFromPathData(
- context.getResources().getString(com.android.internal.R.string.config_icon_mask));
+ mContext.getResources().getString(com.android.internal.R.string.config_icon_mask));
Matrix matrix = new Matrix();
matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
radius /* pivot y */);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index de54c35..08ec789 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -21,6 +21,7 @@
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.Activity;
+import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -32,6 +33,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -39,6 +41,7 @@
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
import java.util.ArrayList;
@@ -103,15 +106,14 @@
- res.getDimensionPixelSize(R.dimen.bubble_overflow_padding);
final int viewHeight = recyclerViewHeight / rows;
- mAdapter = new BubbleOverflowAdapter(mOverflowBubbles,
+ mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles,
mBubbleController::promoteBubbleFromOverflow, viewWidth, viewHeight);
mRecyclerView.setAdapter(mAdapter);
-
- mOverflowBubbles.addAll(mBubbleController.getOverflowBubbles());
- mAdapter.notifyDataSetChanged();
- setEmptyStateVisibility();
-
- mBubbleController.setOverflowListener(mDataListener);
+ onDataChanged(mBubbleController.getOverflowBubbles());
+ mBubbleController.setOverflowCallback(() -> {
+ onDataChanged(mBubbleController.getOverflowBubbles());
+ });
+ onThemeChanged();
}
/**
@@ -138,14 +140,6 @@
}
}
- void setEmptyStateVisibility() {
- if (mOverflowBubbles.isEmpty()) {
- mEmptyState.setVisibility(View.VISIBLE);
- } else {
- mEmptyState.setVisibility(View.GONE);
- }
- }
-
void setBackgroundColor() {
final TypedArray ta = getApplicationContext().obtainStyledAttributes(
new int[]{android.R.attr.colorBackgroundFloating});
@@ -154,40 +148,22 @@
findViewById(android.R.id.content).setBackgroundColor(bgColor);
}
- private final BubbleData.Listener mDataListener = new BubbleData.Listener() {
+ void onDataChanged(List<Bubble> bubbles) {
+ mOverflowBubbles.clear();
+ mOverflowBubbles.addAll(bubbles);
+ mAdapter.notifyDataSetChanged();
- @Override
- public void applyUpdate(BubbleData.Update update) {
-
- Bubble toRemove = update.removedOverflowBubble;
- if (toRemove != null) {
- if (DEBUG_OVERFLOW) {
- Log.d(TAG, "remove: " + toRemove);
- }
- toRemove.cleanupViews();
- int i = mOverflowBubbles.indexOf(toRemove);
- mOverflowBubbles.remove(toRemove);
- mAdapter.notifyItemRemoved(i);
- }
-
- Bubble toAdd = update.addedOverflowBubble;
- if (toAdd != null) {
- if (DEBUG_OVERFLOW) {
- Log.d(TAG, "add: " + toAdd);
- }
- mOverflowBubbles.add(0, toAdd);
- mAdapter.notifyItemInserted(0);
- }
-
- setEmptyStateVisibility();
-
- if (DEBUG_OVERFLOW) {
- Log.d(TAG, BubbleDebugConfig.formatBubblesString(
- mBubbleController.getOverflowBubbles(),
- null));
- }
+ if (mOverflowBubbles.isEmpty()) {
+ mEmptyState.setVisibility(View.VISIBLE);
+ } else {
+ mEmptyState.setVisibility(View.GONE);
}
- };
+
+ if (DEBUG_OVERFLOW) {
+ Log.d(TAG, "Updated overflow bubbles:\n" + BubbleDebugConfig.formatBubblesString(
+ mOverflowBubbles, /*selected*/ null));
+ }
+ }
@Override
public void onStart() {
@@ -221,13 +197,15 @@
}
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
+ private Context mContext;
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
private int mWidth;
private int mHeight;
- public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble, int width,
- int height) {
+ public BubbleOverflowAdapter(Context context, List<Bubble> list, Consumer<Bubble> promoteBubble,
+ int width, int height) {
+ mContext = context;
mBubbles = list;
mPromoteBubbleFromOverflow = promoteBubble;
mWidth = width;
@@ -237,6 +215,8 @@
@Override
public BubbleOverflowAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
+
+ // Set layout for overflow bubble view.
LinearLayout overflowView = (LinearLayout) LayoutInflater.from(parent.getContext())
.inflate(R.layout.bubble_overflow_view, parent, false);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
@@ -245,6 +225,18 @@
params.width = mWidth;
params.height = mHeight;
overflowView.setLayoutParams(params);
+
+ // Ensure name has enough contrast.
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{android.R.attr.colorBackgroundFloating, android.R.attr.textColorPrimary});
+ final int bgColor = ta.getColor(0, Color.WHITE);
+ int textColor = ta.getColor(1, Color.BLACK);
+ textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true);
+ ta.recycle();
+
+ TextView viewName = overflowView.findViewById(R.id.bubble_view_name);
+ viewName.setTextColor(textColor);
+
return new ViewHolder(overflowView);
}
@@ -260,6 +252,32 @@
mPromoteBubbleFromOverflow.accept(b);
});
+ final CharSequence titleCharSeq =
+ b.getEntry().getSbn().getNotification().extras.getCharSequence(
+ Notification.EXTRA_TITLE);
+ String titleStr = mContext.getResources().getString(R.string.notification_bubble_title);
+ if (titleCharSeq != null) {
+ titleStr = titleCharSeq.toString();
+ }
+ vh.iconView.setContentDescription(mContext.getResources().getString(
+ R.string.bubble_content_description_single, titleStr, b.getAppName()));
+
+ vh.iconView.setAccessibilityDelegate(
+ new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // Talkback prompts "Double tap to add back to stack"
+ // instead of the default "Double tap to activate"
+ info.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK,
+ mContext.getResources().getString(
+ R.string.bubble_accessibility_action_add_back)));
+ }
+ });
+
Bubble.FlyoutMessage message = b.getFlyoutMessage();
if (message != null && message.senderName != null) {
vh.textView.setText(message.senderName);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 35ac78d..88f5eb0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -445,6 +445,10 @@
final boolean clickedBubbleIsCurrentlyExpandedBubble =
clickedBubble.getKey().equals(mExpandedBubble.getKey());
+ if (isExpanded()) {
+ mExpandedAnimationController.onGestureFinished();
+ }
+
if (isExpanded() && !clickedBubbleIsCurrentlyExpandedBubble) {
if (clickedBubble != mBubbleData.getSelectedBubble()) {
// Select the clicked bubble.
@@ -454,7 +458,6 @@
// that means overflow was previously expanded. Set the selected bubble
// internally without going through BubbleData (which would ignore it since it's
// already selected).
- mBubbleData.setShowingOverflow(true);
setSelectedBubble(clickedBubble);
}
} else {
@@ -465,7 +468,6 @@
mBubbleData.setExpanded(!mBubbleData.isExpanded());
}
}
- mExpandedAnimationController.onGestureFinished();
}
};
@@ -788,8 +790,8 @@
mOrientationChangedListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- mExpandedAnimationController.updateOrientation(mOrientation, mDisplaySize);
- mStackAnimationController.updateOrientation(mOrientation);
+ mExpandedAnimationController.updateResources(mOrientation, mDisplaySize);
+ mStackAnimationController.updateResources(mOrientation);
// Reposition & adjust the height for new orientation
if (mIsExpanded) {
@@ -1005,7 +1007,7 @@
mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
} else {
mBubbleContainer.removeView(mBubbleOverflow.getBtn());
- mBubbleOverflow.updateIcon(mContext, this);
+ mBubbleOverflow.updateIcon(mContext,this);
overflowBtnIndex = mBubbleContainer.getChildCount();
}
mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
@@ -1052,10 +1054,33 @@
mShowingManage = false;
}
+ /** Respond to the display size change by recalculating view size and location. */
+ public void onDisplaySizeChanged() {
+ setUpOverflow();
+
+ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getRealSize(mDisplaySize);
+ Resources res = getContext().getResources();
+ mStatusBarHeight = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
+ mBubbleSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size);
+ for (Bubble b : mBubbleData.getBubbles()) {
+ if (b.getIconView() == null) {
+ Log.d(TAG, "Display size changed. Icon null: " + b);
+ continue;
+ }
+ b.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize));
+ }
+ mExpandedAnimationController.updateResources(mOrientation, mDisplaySize);
+ mStackAnimationController.updateResources(mOrientation);
+ }
+
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ mTempRect.setEmpty();
getTouchableRegion(mTempRect);
inoutInfo.touchableRegion.set(mTempRect);
}
@@ -1076,26 +1101,27 @@
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
+ setupLocalMenu(info);
+ }
- // Custom actions.
+ void setupLocalMenu(AccessibilityNodeInfo info) {
+ Resources res = mContext.getResources();
+
+ // Custom local actions.
AccessibilityAction moveTopLeft = new AccessibilityAction(R.id.action_move_top_left,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_top_left));
+ res.getString(R.string.bubble_accessibility_action_move_top_left));
info.addAction(moveTopLeft);
AccessibilityAction moveTopRight = new AccessibilityAction(R.id.action_move_top_right,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_top_right));
+ res.getString(R.string.bubble_accessibility_action_move_top_right));
info.addAction(moveTopRight);
AccessibilityAction moveBottomLeft = new AccessibilityAction(R.id.action_move_bottom_left,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_bottom_left));
+ res.getString(R.string.bubble_accessibility_action_move_bottom_left));
info.addAction(moveBottomLeft);
AccessibilityAction moveBottomRight = new AccessibilityAction(R.id.action_move_bottom_right,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_bottom_right));
+ res.getString(R.string.bubble_accessibility_action_move_bottom_right));
info.addAction(moveBottomRight);
// Default actions.
@@ -1290,7 +1316,7 @@
Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
}
- private void updateOverflowBtnVisibility(boolean apply) {
+ private void updateOverflowBtnVisibility() {
if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
return;
}
@@ -1299,11 +1325,6 @@
Log.d(TAG, "Show overflow button.");
}
mBubbleOverflow.setBtnVisible(VISIBLE);
- if (apply) {
- mExpandedAnimationController.expandFromStack(() -> {
- updatePointerPosition();
- } /* after */);
- }
} else {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "Collapsed. Hide overflow button.");
@@ -1343,7 +1364,10 @@
}
if (bubbleToSelect == null || bubbleToSelect.getKey() != BubbleOverflow.KEY) {
mBubbleData.setShowingOverflow(false);
+ } else {
+ mBubbleData.setShowingOverflow(true);
}
+
final BubbleViewProvider previouslySelected = mExpandedBubble;
mExpandedBubble = bubbleToSelect;
updatePointerPosition();
@@ -1560,7 +1584,7 @@
Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
mExpandedBubble));
}
- updateOverflowBtnVisibility(/* apply */ false);
+ updateOverflowBtnVisibility();
mBubbleContainer.cancelAllAnimations();
mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
@@ -1584,7 +1608,7 @@
beforeExpandedViewAnimation();
mBubbleContainer.setActiveController(mExpandedAnimationController);
- updateOverflowBtnVisibility(/* apply */ false);
+ updateOverflowBtnVisibility();
mExpandedAnimationController.expandFromStack(() -> {
updatePointerPosition();
afterExpandedViewAnimation();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 35406c7..f57cf42 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -118,7 +118,7 @@
public ExpandedAnimationController(Point displaySize, int expandedViewPadding,
int orientation) {
- updateOrientation(orientation, displaySize);
+ updateResources(orientation, displaySize);
mExpandedViewPadding = expandedViewPadding;
}
@@ -168,7 +168,7 @@
* @param orientation Landscape or portrait.
* @param displaySize Updated display size.
*/
- public void updateOrientation(int orientation, Point displaySize) {
+ public void updateResources(int orientation, Point displaySize) {
mScreenOrientation = orientation;
mDisplaySize = displaySize;
if (mLayout != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 5f3a2bd..2cfe1dd 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -809,7 +809,7 @@
* Update effective screen width based on current orientation.
* @param orientation Landscape or portrait.
*/
- public void updateOrientation(int orientation) {
+ public void updateResources(int orientation) {
if (mLayout != null) {
Resources res = mLayout.getContext().getResources();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index e3b630b..d1d07f6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -18,6 +18,7 @@
import android.app.INotificationManager;
import android.content.Context;
+import android.view.WindowManager;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubbleData;
@@ -68,7 +69,8 @@
FloatingContentCoordinator floatingContentCoordinator,
BubbleDataRepository bubbleDataRepository,
SysUiState sysUiState,
- INotificationManager notifManager) {
+ INotificationManager notifManager,
+ WindowManager windowManager) {
return new BubbleController(
context,
notificationShadeWindowController,
@@ -88,6 +90,7 @@
floatingContentCoordinator,
bubbleDataRepository,
sysUiState,
- notifManager);
+ notifManager,
+ windowManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
rename to packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
index d0f7607..4690a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
@@ -17,7 +17,7 @@
import android.annotation.UserIdInt
-data class BubbleXmlEntity(
+data class BubbleEntity(
@UserIdInt val userId: Int,
val packageName: String,
val shortcutId: String
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
index b2495c6..7c3271e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
@@ -32,7 +32,8 @@
private val bubbleFile: AtomicFile = AtomicFile(File(context.filesDir,
"overflow_bubbles.xml"), "overflow-bubbles")
- fun persistsToDisk(bubbles: List<BubbleXmlEntity>): Boolean {
+ fun persistsToDisk(bubbles: List<BubbleEntity>): Boolean {
+ if (DEBUG) Log.d(TAG, "persisting ${bubbles.size} bubbles")
synchronized(bubbleFile) {
val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) {
Log.e(TAG, "Failed to save bubble file", e)
@@ -41,6 +42,7 @@
try {
writeXml(stream, bubbles)
bubbleFile.finishWrite(stream)
+ if (DEBUG) Log.d(TAG, "persisted ${bubbles.size} bubbles")
return true
} catch (e: Exception) {
Log.e(TAG, "Failed to save bubble file, restoring backup", e)
@@ -49,6 +51,16 @@
}
return false
}
+
+ fun readFromDisk(): List<BubbleEntity> {
+ synchronized(bubbleFile) {
+ try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) {
+ Log.e(TAG, "Failed to open bubble file", e)
+ }
+ return emptyList()
+ }
+ }
}
private const val TAG = "BubblePersistentRepository"
+private const val DEBUG = false
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
index 3dba268..d1eee2f6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
@@ -29,37 +29,31 @@
/**
* An ordered set of bubbles based on their natural ordering.
*/
- private val entities = mutableSetOf<BubbleXmlEntity>()
+ private val entities = mutableSetOf<BubbleEntity>()
/**
* Returns a snapshot of all the bubbles.
*/
- val bubbles: List<BubbleXmlEntity>
+ val bubbles: List<BubbleEntity>
@Synchronized
get() = entities.toList()
/**
- * Add the bubble to memory and perform a de-duplication. In case the bubble already exists,
- * the bubble will be moved to the last.
- */
- fun addBubble(bubble: BubbleXmlEntity) = addBubbles(listOf(bubble))
-
- /**
* Add the bubbles to memory and perform a de-duplication. In case a bubble already exists,
* it will be moved to the last.
*/
@Synchronized
- fun addBubbles(bubbles: List<BubbleXmlEntity>) {
+ fun addBubbles(bubbles: List<BubbleEntity>) {
if (bubbles.isEmpty()) return
bubbles.forEach { entities.remove(it) }
if (entities.size + bubbles.size >= CAPACITY) {
entities.drop(entities.size + bubbles.size - CAPACITY)
}
- entities.addAll(bubbles.reversed())
+ entities.addAll(bubbles)
}
@Synchronized
- fun removeBubbles(bubbles: List<BubbleXmlEntity>) {
+ fun removeBubbles(bubbles: List<BubbleEntity>) {
bubbles.forEach { entities.remove(it) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
index 3192f34b..821b64c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
@@ -18,6 +18,10 @@
import com.android.internal.util.FastXmlSerializer
import org.xmlpull.v1.XmlSerializer
import java.io.IOException
+import android.util.Xml
+import com.android.internal.util.XmlUtils
+import org.xmlpull.v1.XmlPullParser
+import java.io.InputStream
import java.io.OutputStream
import java.nio.charset.StandardCharsets
@@ -31,7 +35,7 @@
* Writes the bubbles in xml format into given output stream.
*/
@Throws(IOException::class)
-fun writeXml(stream: OutputStream, bubbles: List<BubbleXmlEntity>) {
+fun writeXml(stream: OutputStream, bubbles: List<BubbleEntity>) {
val serializer: XmlSerializer = FastXmlSerializer()
serializer.setOutput(stream, StandardCharsets.UTF_8.name())
serializer.startDocument(null, true)
@@ -47,7 +51,7 @@
* <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" />
* ```
*/
-private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) {
+private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
try {
serializer.startTag(null, TAG_BUBBLE)
serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString())
@@ -57,4 +61,35 @@
} catch (e: IOException) {
throw RuntimeException(e)
}
+}
+
+/**
+ * Reads the bubbles from xml file.
+ */
+fun readXml(stream: InputStream): List<BubbleEntity> {
+ val bubbles = mutableListOf<BubbleEntity>()
+ val parser: XmlPullParser = Xml.newPullParser()
+ parser.setInput(stream, StandardCharsets.UTF_8.name())
+ XmlUtils.beginDocument(parser, TAG_BUBBLES)
+ val outerDepth = parser.depth
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ bubbles.add(readXmlEntry(parser) ?: continue)
+ }
+ return bubbles
+}
+
+private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? {
+ while (parser.eventType != XmlPullParser.START_TAG) { parser.next() }
+ return BubbleEntity(
+ parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null,
+ parser.getAttributeWithName(ATTR_PACKAGE) ?: return null,
+ parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null
+ )
+}
+
+private fun XmlPullParser.getAttributeWithName(name: String): String? {
+ for (i in 0 until attributeCount) {
+ if (getAttributeName(i) == name) return getAttributeValue(i)
+ }
+ return null
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
index 175ed06..00a406e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
@@ -48,6 +48,8 @@
private var modified = false
+ override val moveHelper = null
+
override val favorites: List<ControlInfo>
get() = favoriteIds.mapNotNull { id ->
val control = controls.firstOrNull { it.control.controlId == id }?.control
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 79dd9ed..2f91710 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -18,14 +18,20 @@
import android.content.ComponentName
import android.graphics.Rect
+import android.os.Bundle
import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.view.accessibility.AccessibilityNodeInfo
import android.widget.CheckBox
import android.widget.ImageView
+import android.widget.Switch
import android.widget.TextView
+import androidx.core.view.AccessibilityDelegateCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
@@ -72,7 +78,8 @@
elevation = this@ControlAdapter.elevation
background = parent.context.getDrawable(
R.drawable.control_background_ripple)
- }
+ },
+ model?.moveHelper // Indicates that position information is needed
) { id, favorite ->
model?.changeFavoriteStatus(id, favorite)
}
@@ -170,13 +177,21 @@
/**
* Holder for using with [ControlStatusWrapper] to display names of zones.
+ * @param moveHelper a helper interface to facilitate a11y rearranging. Null indicates no
+ * rearranging
* @param favoriteCallback this callback will be called whenever the favorite state of the
* [Control] this view represents changes.
*/
internal class ControlHolder(
view: View,
+ val moveHelper: ControlsModel.MoveHelper?,
val favoriteCallback: ModelFavoriteChanger
) : Holder(view) {
+ private val favoriteStateDescription =
+ itemView.context.getString(R.string.accessibility_control_favorite)
+ private val notFavoriteStateDescription =
+ itemView.context.getString(R.string.accessibility_control_not_favorite)
+
private val icon: ImageView = itemView.requireViewById(R.id.icon)
private val title: TextView = itemView.requireViewById(R.id.title)
private val subtitle: TextView = itemView.requireViewById(R.id.subtitle)
@@ -185,15 +200,42 @@
visibility = View.VISIBLE
}
+ private val accessibilityDelegate = ControlHolderAccessibilityDelegate(
+ this::stateDescription,
+ this::getLayoutPosition,
+ moveHelper
+ )
+
+ init {
+ ViewCompat.setAccessibilityDelegate(itemView, accessibilityDelegate)
+ }
+
+ // Determine the stateDescription based on favorite state and maybe position
+ private fun stateDescription(favorite: Boolean): CharSequence? {
+ if (!favorite) {
+ return notFavoriteStateDescription
+ } else if (moveHelper == null) {
+ return favoriteStateDescription
+ } else {
+ val position = layoutPosition + 1
+ return itemView.context.getString(
+ R.string.accessibility_control_favorite_position, position)
+ }
+ }
+
override fun bindData(wrapper: ElementWrapper) {
wrapper as ControlInterface
val renderInfo = getRenderInfo(wrapper.component, wrapper.deviceType)
title.text = wrapper.title
subtitle.text = wrapper.subtitle
- favorite.isChecked = wrapper.favorite
- removed.text = if (wrapper.removed) "Removed" else ""
+ updateFavorite(wrapper.favorite)
+ removed.text = if (wrapper.removed) {
+ itemView.context.getText(R.string.controls_removed)
+ } else {
+ ""
+ }
itemView.setOnClickListener {
- favorite.isChecked = !favorite.isChecked
+ updateFavorite(!favorite.isChecked)
favoriteCallback(wrapper.controlId, favorite.isChecked)
}
applyRenderInfo(renderInfo)
@@ -201,6 +243,8 @@
override fun updateFavorite(favorite: Boolean) {
this.favorite.isChecked = favorite
+ accessibilityDelegate.isFavorite = favorite
+ itemView.stateDescription = stateDescription(favorite)
}
private fun getRenderInfo(
@@ -219,6 +263,105 @@
}
}
+/**
+ * Accessibility delegate for [ControlHolder].
+ *
+ * Provides the following functionality:
+ * * Sets the state description indicating whether the controls is Favorited or Unfavorited
+ * * Adds the position to the state description if necessary.
+ * * Adds context action for moving (rearranging) a control.
+ *
+ * @param stateRetriever function to determine the state description based on the favorite state
+ * @param positionRetriever function to obtain the position of this control. It only has to be
+ * correct in controls that are currently favorites (and therefore can
+ * be moved).
+ * @param moveHelper helper interface to determine if a control can be moved and actually move it.
+ */
+private class ControlHolderAccessibilityDelegate(
+ val stateRetriever: (Boolean) -> CharSequence?,
+ val positionRetriever: () -> Int,
+ val moveHelper: ControlsModel.MoveHelper?
+) : AccessibilityDelegateCompat() {
+
+ var isFavorite = false
+
+ companion object {
+ private val MOVE_BEFORE_ID = R.id.accessibility_action_controls_move_before
+ private val MOVE_AFTER_ID = R.id.accessibility_action_controls_move_after
+ }
+
+ override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
+ super.onInitializeAccessibilityNodeInfo(host, info)
+
+ info.isContextClickable = false
+ addClickAction(host, info)
+ maybeAddMoveBeforeAction(host, info)
+ maybeAddMoveAfterAction(host, info)
+
+ // Determine the stateDescription based on the holder information
+ info.stateDescription = stateRetriever(isFavorite)
+ // Remove the information at the end indicating row and column.
+ info.setCollectionItemInfo(null)
+
+ info.className = Switch::class.java.name
+ }
+
+ override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
+ if (super.performAccessibilityAction(host, action, args)) {
+ return true
+ }
+ return when (action) {
+ MOVE_BEFORE_ID -> {
+ moveHelper?.moveBefore(positionRetriever())
+ true
+ }
+ MOVE_AFTER_ID -> {
+ moveHelper?.moveAfter(positionRetriever())
+ true
+ }
+ else -> false
+ }
+ }
+
+ private fun addClickAction(host: View, info: AccessibilityNodeInfoCompat) {
+ // Change the text for the double-tap action
+ val clickActionString = if (isFavorite) {
+ host.context.getString(R.string.accessibility_control_change_unfavorite)
+ } else {
+ host.context.getString(R.string.accessibility_control_change_favorite)
+ }
+ val click = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
+ AccessibilityNodeInfo.ACTION_CLICK,
+ // “favorite/unfavorite”
+ clickActionString)
+ info.addAction(click)
+ }
+
+ private fun maybeAddMoveBeforeAction(host: View, info: AccessibilityNodeInfoCompat) {
+ if (moveHelper?.canMoveBefore(positionRetriever()) ?: false) {
+ val newPosition = positionRetriever() + 1 - 1
+ val moveBefore = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
+ MOVE_BEFORE_ID,
+ host.context.getString(R.string.accessibility_control_move, newPosition)
+ )
+ info.addAction(moveBefore)
+ info.isContextClickable = true
+ }
+ }
+
+ private fun maybeAddMoveAfterAction(host: View, info: AccessibilityNodeInfoCompat) {
+ if (moveHelper?.canMoveAfter(positionRetriever()) ?: false) {
+ val newPosition = positionRetriever() + 1 + 1
+ val moveAfter = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
+ MOVE_AFTER_ID,
+ host.context.getString(R.string.accessibility_control_move, newPosition)
+ )
+ info.addAction(moveAfter)
+ info.isContextClickable = true
+ }
+ }
+}
+
class MarginItemDecorator(
private val topMargin: Int,
private val sideMargins: Int
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index 4e9c550..ff40a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -130,6 +130,7 @@
inflate()
}
requireViewById<TextView>(R.id.title).text = structure
+ setTitle(structure)
subtitle = requireViewById<TextView>(R.id.subtitle).apply {
setText(SUBTITLE_ID)
}
@@ -191,7 +192,18 @@
recyclerView.apply {
this.adapter = adapter
- layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
+ layoutManager = object : GridLayoutManager(recyclerView.context, 2) {
+
+ // This will remove from the announcement the row corresponding to the divider,
+ // as it's not something that should be announced.
+ override fun getRowCountForAccessibility(
+ recycler: RecyclerView.Recycler,
+ state: RecyclerView.State
+ ): Int {
+ val initial = super.getRowCountForAccessibility(recycler, state)
+ return if (initial > 0) initial - 1 else initial
+ }
+ }.apply {
spanSizeLookup = adapter.spanSizeLookup
}
addItemDecoration(itemDecorator)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index eb15262..496b21b6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -208,7 +208,7 @@
val name = listOfStructures[position].structureName
val title = if (!TextUtils.isEmpty(name)) name else appName
titleView.text = title
- setTitle(title)
+ titleView.requestFocus()
}
override fun onPageScrolled(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 48f191d..a2adcf9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -106,9 +106,15 @@
override fun changeUser(newUser: UserHandle) {
backgroundExecutor.execute {
- callbacks.clear()
- availableServices = emptyList()
serviceListing.setListening(false)
+
+ // Notify all callbacks in order to clear their existing state prior to attaching
+ // a new listener
+ availableServices = emptyList()
+ callbacks.forEach {
+ it.onServicesUpdated(emptyList())
+ }
+
currentUserId = newUser.identifier
val contextForUser = context.createContextAsUser(newUser, 0)
serviceListing = serviceListingBuilder(contextForUser)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
index 37b6d15..2543953 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
@@ -42,6 +42,8 @@
*/
val elements: List<ElementWrapper>
+ val moveHelper: MoveHelper?
+
/**
* Change the favorite status of a particular control.
*/
@@ -69,6 +71,34 @@
*/
fun onFirstChange()
}
+
+ /**
+ * Interface to facilitate moving controls from an [AccessibilityDelegate].
+ *
+ * All positions should be 0 based.
+ */
+ interface MoveHelper {
+
+ /**
+ * Whether the control in `position` can be moved to the position before it.
+ */
+ fun canMoveBefore(position: Int): Boolean
+
+ /**
+ * Whether the control in `position` can be moved to the position after it.
+ */
+ fun canMoveAfter(position: Int): Boolean
+
+ /**
+ * Move the control in `position` to the position before it.
+ */
+ fun moveBefore(position: Int)
+
+ /**
+ * Move the control in `position` to the position after it.
+ */
+ fun moveAfter(position: Int)
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
index 411170cb..5242501 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.content.ComponentName
+import android.util.Log
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.controls.ControlInterface
@@ -39,9 +40,39 @@
private val favoritesModelCallback: FavoritesModelCallback
) : ControlsModel {
+ companion object {
+ private const val TAG = "FavoritesModel"
+ }
+
private var adapter: RecyclerView.Adapter<*>? = null
private var modified = false
+ override val moveHelper = object : ControlsModel.MoveHelper {
+ override fun canMoveBefore(position: Int): Boolean {
+ return position > 0 && position < dividerPosition
+ }
+
+ override fun canMoveAfter(position: Int): Boolean {
+ return position >= 0 && position < dividerPosition - 1
+ }
+
+ override fun moveBefore(position: Int) {
+ if (!canMoveBefore(position)) {
+ Log.w(TAG, "Cannot move position $position before")
+ } else {
+ onMoveItem(position, position - 1)
+ }
+ }
+
+ override fun moveAfter(position: Int) {
+ if (!canMoveAfter(position)) {
+ Log.w(TAG, "Cannot move position $position after")
+ } else {
+ onMoveItem(position, position + 1)
+ }
+ }
+ }
+
override fun attachAdapter(adapter: RecyclerView.Adapter<*>) {
this.adapter = adapter
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt
index 275c778..842c39b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt
@@ -30,6 +30,9 @@
/**
* Will be invoked on every update provided to the Control
+ *
+ * @param cws ControlWithState, as loaded from favorites and/or the application
+ * @param colorOffset An additional flag to control rendering color. See [RenderInfo]
*/
- fun bind(cws: ControlWithState)
+ fun bind(cws: ControlWithState, colorOffset: Int = 0)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
index 1f07e37..6c28d11 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -50,7 +50,8 @@
fun createPinDialog(
cvh: ControlViewHolder,
useAlphaNumeric: Boolean,
- useRetryStrings: Boolean
+ useRetryStrings: Boolean,
+ onCancel: () -> Unit
): Dialog? {
val lastAction = cvh.lastAction
if (lastAction == null) {
@@ -86,7 +87,10 @@
})
setNegativeButton(
android.R.string.cancel,
- DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+ DialogInterface.OnClickListener { dialog, _ ->
+ onCancel.invoke()
+ dialog.cancel()
+ }
)
}
return builder.create().apply {
@@ -111,7 +115,7 @@
/**
* AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type.
*/
- fun createConfirmationDialog(cvh: ControlViewHolder): Dialog? {
+ fun createConfirmationDialog(cvh: ControlViewHolder, onCancel: () -> Unit): Dialog? {
val lastAction = cvh.lastAction
if (lastAction == null) {
Log.e(ControlsUiController.TAG,
@@ -120,7 +124,7 @@
}
val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
val res = cvh.context.resources
- setMessage(res.getString(
+ setTitle(res.getString(
R.string.controls_confirmation_message, cvh.title.getText()))
setPositiveButton(
android.R.string.ok,
@@ -130,7 +134,10 @@
})
setNegativeButton(
android.R.string.cancel,
- DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+ DialogInterface.OnClickListener { dialog, _ ->
+ onCancel.invoke()
+ dialog.cancel()
+ }
)
}
return builder.create().apply {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 2653ce0..f979bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -18,21 +18,28 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
import android.animation.ValueAnimator
+import android.annotation.ColorRes
import android.app.Dialog
import android.content.Context
+import android.content.res.ColorStateList
import android.graphics.drawable.ClipDrawable
+import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.service.controls.actions.ControlAction
import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.RangeTemplate
import android.service.controls.templates.StatelessTemplate
import android.service.controls.templates.TemperatureControlTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.service.controls.templates.ToggleTemplate
import android.util.MathUtils
+import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
@@ -62,6 +69,8 @@
private const val UPDATE_DELAY_IN_MILLIS = 3000L
private const val ALPHA_ENABLED = 255
private const val ALPHA_DISABLED = 0
+ private const val STATUS_ALPHA_ENABLED = 1f
+ private const val STATUS_ALPHA_DIMMED = 0.45f
private val FORCE_PANEL_DEVICES = setOf(
DeviceTypes.TYPE_THERMOSTAT,
DeviceTypes.TYPE_CAMERA
@@ -69,14 +78,35 @@
const val MIN_LEVEL = 0
const val MAX_LEVEL = 10000
+
+ fun findBehaviorClass(
+ status: Int,
+ template: ControlTemplate,
+ deviceType: Int
+ ): KClass<out Behavior> {
+ return when {
+ status == Control.STATUS_UNKNOWN -> StatusBehavior::class
+ status == Control.STATUS_ERROR -> StatusBehavior::class
+ status == Control.STATUS_NOT_FOUND -> StatusBehavior::class
+ deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
+ template is ToggleTemplate -> ToggleBehavior::class
+ template is StatelessTemplate -> TouchBehavior::class
+ template is ToggleRangeTemplate -> ToggleRangeBehavior::class
+ template is RangeTemplate -> ToggleRangeBehavior::class
+ template is TemperatureControlTemplate -> TemperatureControlBehavior::class
+ else -> DefaultBehavior::class
+ }
+ }
}
private val toggleBackgroundIntensity: Float = layout.context.resources
.getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1)
private var stateAnimator: ValueAnimator? = null
+ private var statusAnimator: Animator? = null
private val baseLayer: GradientDrawable
val icon: ImageView = layout.requireViewById(R.id.icon)
- val status: TextView = layout.requireViewById(R.id.status)
+ private val status: TextView = layout.requireViewById(R.id.status)
+ private var nextStatusText: CharSequence = ""
val title: TextView = layout.requireViewById(R.id.title)
val subtitle: TextView = layout.requireViewById(R.id.subtitle)
val context: Context = layout.getContext()
@@ -85,7 +115,9 @@
var cancelUpdate: Runnable? = null
var behavior: Behavior? = null
var lastAction: ControlAction? = null
+ var isLoading = false
private var lastChallengeDialog: Dialog? = null
+ private val onDialogCancel: () -> Unit = { lastChallengeDialog = null }
val deviceType: Int
get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
@@ -123,20 +155,9 @@
})
}
- val clazz = findBehavior(controlStatus, template, deviceType)
- if (behavior == null || behavior!!::class != clazz) {
- // Behavior changes can signal a change in template from the app or
- // first time setup
- behavior = clazz.java.newInstance()
- behavior?.initialize(this)
-
- // let behaviors define their own, if necessary, and clear any existing ones
- layout.setAccessibilityDelegate(null)
- }
-
- behavior?.bind(cws)
-
- layout.setContentDescription("${title.text} ${subtitle.text} ${status.text}")
+ isLoading = false
+ behavior = bindBehavior(behavior, findBehaviorClass(controlStatus, template, deviceType))
+ updateContentDescription()
}
fun actionResponse(@ControlAction.ResponseResult response: Int) {
@@ -154,15 +175,18 @@
setTransientStatus(context.resources.getString(R.string.controls_error_failed))
}
ControlAction.RESPONSE_CHALLENGE_PIN -> {
- lastChallengeDialog = ChallengeDialogs.createPinDialog(this, false, failedAttempt)
+ lastChallengeDialog = ChallengeDialogs.createPinDialog(
+ this, false, failedAttempt, onDialogCancel)
lastChallengeDialog?.show()
}
ControlAction.RESPONSE_CHALLENGE_PASSPHRASE -> {
- lastChallengeDialog = ChallengeDialogs.createPinDialog(this, true, failedAttempt)
+ lastChallengeDialog = ChallengeDialogs.createPinDialog(
+ this, false, failedAttempt, onDialogCancel)
lastChallengeDialog?.show()
}
ControlAction.RESPONSE_CHALLENGE_ACK -> {
- lastChallengeDialog = ChallengeDialogs.createConfirmationDialog(this)
+ lastChallengeDialog = ChallengeDialogs.createConfirmationDialog(
+ this, onDialogCancel)
lastChallengeDialog?.show()
}
}
@@ -177,12 +201,17 @@
val previousText = status.getText()
cancelUpdate = uiExecutor.executeDelayed({
- status.setText(previousText)
- }, UPDATE_DELAY_IN_MILLIS)
+ setStatusText(previousText)
+ updateContentDescription()
+ }, UPDATE_DELAY_IN_MILLIS)
- status.setText(tempStatus)
+ setStatusText(tempStatus)
+ updateContentDescription()
}
+ private fun updateContentDescription() =
+ layout.setContentDescription("${title.text} ${subtitle.text} ${status.text}")
+
fun action(action: ControlAction) {
lastAction = action
controlsController.action(cws.componentName, cws.ci, action)
@@ -190,37 +219,74 @@
fun usePanel(): Boolean = deviceType in ControlViewHolder.FORCE_PANEL_DEVICES
- private fun findBehavior(
- status: Int,
- template: ControlTemplate,
- deviceType: Int
- ): KClass<out Behavior> {
- return when {
- status == Control.STATUS_UNKNOWN -> StatusBehavior::class
- status == Control.STATUS_ERROR -> StatusBehavior::class
- status == Control.STATUS_NOT_FOUND -> StatusBehavior::class
- deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
- template is ToggleTemplate -> ToggleBehavior::class
- template is StatelessTemplate -> TouchBehavior::class
- template is ToggleRangeTemplate -> ToggleRangeBehavior::class
- template is TemperatureControlTemplate -> TemperatureControlBehavior::class
- else -> DefaultBehavior::class
+ fun bindBehavior(
+ existingBehavior: Behavior?,
+ clazz: KClass<out Behavior>,
+ offset: Int = 0
+ ): Behavior {
+ val behavior = if (existingBehavior == null || existingBehavior!!::class != clazz) {
+ // Behavior changes can signal a change in template from the app or
+ // first time setup
+ val newBehavior = clazz.java.newInstance()
+ newBehavior.initialize(this)
+
+ // let behaviors define their own, if necessary, and clear any existing ones
+ layout.setAccessibilityDelegate(null)
+ newBehavior
+ } else {
+ existingBehavior
+ }
+
+ return behavior.also {
+ it.bind(cws, offset)
}
}
- internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0, animated: Boolean = true) {
- setEnabled(enabled)
-
+ internal fun applyRenderInfo(enabled: Boolean, offset: Int, animated: Boolean = true) {
val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
-
val fg = context.resources.getColorStateList(ri.foreground, context.theme)
+ val newText = nextStatusText
+ nextStatusText = ""
+ val control = cws.control
+
+ var shouldAnimate = animated
+ if (newText == status.text) {
+ shouldAnimate = false
+ }
+ animateStatusChange(shouldAnimate) {
+ updateStatusRow(enabled, newText, ri.icon, fg, control)
+ }
+
+ animateBackgroundChange(shouldAnimate, enabled, ri.enabledBackground)
+ }
+
+ fun getStatusText() = status.text
+
+ fun setStatusTextSize(textSize: Float) =
+ status.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
+
+ fun setStatusText(text: CharSequence, immediately: Boolean = false) {
+ if (immediately) {
+ status.alpha = STATUS_ALPHA_ENABLED
+ status.text = text
+ nextStatusText = ""
+ } else {
+ nextStatusText = text
+ }
+ }
+
+ private fun animateBackgroundChange(
+ animated: Boolean,
+ enabled: Boolean,
+ @ColorRes bgColor: Int
+ ) {
val bg = context.resources.getColor(R.color.control_default_background, context.theme)
var (newClipColor, newAlpha) = if (enabled) {
// allow color overrides for the enabled state only
val color = cws.control?.getCustomColor()?.let {
val state = intArrayOf(android.R.attr.state_enabled)
it.getColorForState(state, it.getDefaultColor())
- } ?: context.resources.getColor(ri.enabledBackground, context.theme)
+ } ?: context.resources.getColor(bgColor, context.theme)
listOf(color, ALPHA_ENABLED)
} else {
listOf(
@@ -229,21 +295,6 @@
)
}
- status.setTextColor(fg)
-
- cws.control?.getCustomIcon()?.let {
- // do not tint custom icons, assume the intended icon color is correct
- icon.imageTintList = null
- icon.setImageIcon(it)
- } ?: run {
- icon.setImageDrawable(ri.icon)
-
- // do not color app icons
- if (deviceType != DeviceTypes.TYPE_ROUTINE) {
- icon.imageTintList = fg
- }
- }
-
(clipLayer.getDrawable() as GradientDrawable).apply {
val newBaseColor = if (behavior is ToggleRangeBehavior) {
ColorUtils.blendARGB(bg, newClipColor, toggleBackgroundIntensity)
@@ -281,6 +332,77 @@
}
}
+ private fun animateStatusChange(animated: Boolean, statusRowUpdater: () -> Unit) {
+ statusAnimator?.cancel()
+
+ if (!animated) {
+ statusRowUpdater.invoke()
+ return
+ }
+
+ if (isLoading) {
+ statusRowUpdater.invoke()
+ statusAnimator = ObjectAnimator.ofFloat(status, "alpha", STATUS_ALPHA_DIMMED).apply {
+ repeatMode = ValueAnimator.REVERSE
+ repeatCount = ValueAnimator.INFINITE
+ duration = 500L
+ interpolator = Interpolators.LINEAR
+ startDelay = 900L
+ start()
+ }
+ } else {
+ val fadeOut = ObjectAnimator.ofFloat(status, "alpha", 0f).apply {
+ duration = 200L
+ interpolator = Interpolators.LINEAR
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ statusRowUpdater.invoke()
+ }
+ })
+ }
+ val fadeIn = ObjectAnimator.ofFloat(status, "alpha", STATUS_ALPHA_ENABLED).apply {
+ duration = 200L
+ interpolator = Interpolators.LINEAR
+ }
+ statusAnimator = AnimatorSet().apply {
+ playSequentially(fadeOut, fadeIn)
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ status.alpha = STATUS_ALPHA_ENABLED
+ statusAnimator = null
+ }
+ })
+ start()
+ }
+ }
+ }
+
+ private fun updateStatusRow(
+ enabled: Boolean,
+ text: CharSequence,
+ drawable: Drawable,
+ color: ColorStateList,
+ control: Control?
+ ) {
+ setEnabled(enabled)
+
+ status.text = text
+ status.setTextColor(color)
+
+ control?.getCustomIcon()?.let {
+ // do not tint custom icons, assume the intended icon color is correct
+ icon.imageTintList = null
+ icon.setImageIcon(it)
+ } ?: run {
+ icon.setImageDrawable(drawable)
+
+ // do not color app icons
+ if (deviceType != DeviceTypes.TYPE_ROUTINE) {
+ icon.imageTintList = color
+ }
+ }
+ }
+
private fun setEnabled(enabled: Boolean) {
status.setEnabled(enabled)
icon.setEnabled(enabled)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
index e850a6a..0c8e3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
@@ -23,8 +23,8 @@
this.cvh = cvh
}
- override fun bind(cws: ControlWithState) {
- cvh.status.setText(cws.control?.getStatusText() ?: "")
- cvh.applyRenderInfo(false)
+ override fun bind(cws: ControlWithState, colorOffset: Int) {
+ cvh.setStatusText(cws.control?.getStatusText() ?: "")
+ cvh.applyRenderInfo(false, colorOffset)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 124df32..ba331f4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -97,6 +97,8 @@
private const val THERMOSTAT_RANGE = DeviceTypes.TYPE_THERMOSTAT * BUCKET_SIZE
private val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
+ (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_OFF) to
+ Pair(R.color.control_default_foreground, R.color.control_default_background),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to
Pair(R.color.thermo_heat_foreground, R.color.control_enabled_thermo_heat_background),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to
@@ -108,13 +110,9 @@
}
private val deviceIconMap = mapOf<Int, IconState>(
- THERMOSTAT_RANGE to IconState(
- R.drawable.ic_device_thermostat_off,
- R.drawable.ic_device_thermostat_on
- ),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_OFF) to IconState(
R.drawable.ic_device_thermostat_off,
- R.drawable.ic_device_thermostat_on
+ R.drawable.ic_device_thermostat_off
),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to IconState(
R.drawable.ic_device_thermostat_off,
@@ -130,7 +128,7 @@
),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_ECO) to IconState(
R.drawable.ic_device_thermostat_off,
- R.drawable.ic_device_thermostat_on
+ R.drawable.ic_device_thermostat_off
),
DeviceTypes.TYPE_THERMOSTAT to IconState(
R.drawable.ic_device_thermostat_off,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
index 49c4408..bf3835d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
@@ -27,14 +27,17 @@
this.cvh = cvh
}
- override fun bind(cws: ControlWithState) {
+ override fun bind(cws: ControlWithState, colorOffset: Int) {
val status = cws.control?.status ?: Control.STATUS_UNKNOWN
val msg = when (status) {
Control.STATUS_ERROR -> R.string.controls_error_generic
Control.STATUS_NOT_FOUND -> R.string.controls_error_removed
- else -> com.android.internal.R.string.loading
+ else -> {
+ cvh.isLoading = true
+ com.android.internal.R.string.loading
+ }
}
- cvh.status.setText(cvh.context.getString(msg))
- cvh.applyRenderInfo(false)
+ cvh.setStatusText(cvh.context.getString(msg))
+ cvh.applyRenderInfo(false, colorOffset)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index b4d0e63..a7dc09b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -19,6 +19,7 @@
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
+import android.service.controls.templates.ControlTemplate
import android.service.controls.templates.TemperatureControlTemplate
import com.android.systemui.R
@@ -29,29 +30,46 @@
lateinit var clipLayer: Drawable
lateinit var control: Control
lateinit var cvh: ControlViewHolder
- lateinit var template: TemperatureControlTemplate
+ var subBehavior: Behavior? = null
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
-
- cvh.layout.setOnClickListener { _ ->
- cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control)
- }
}
- override fun bind(cws: ControlWithState) {
+ override fun bind(cws: ControlWithState, colorOffset: Int) {
this.control = cws.control!!
- cvh.status.setText(control.getStatusText())
+ cvh.setStatusText(control.getStatusText())
val ld = cvh.layout.getBackground() as LayerDrawable
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
- template = control.getControlTemplate() as TemperatureControlTemplate
-
+ val template = control.getControlTemplate() as TemperatureControlTemplate
val activeMode = template.getCurrentActiveMode()
- val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
- clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
- cvh.applyRenderInfo(enabled, activeMode)
+ val subTemplate = template.getTemplate()
+ if (subTemplate == ControlTemplate.getNoTemplateObject() ||
+ subTemplate == ControlTemplate.getErrorTemplate()) {
+ // No sub template is specified, apply a default look with basic touch interaction.
+ // Treat an error as no template.
+ val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
+ clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
+ cvh.applyRenderInfo(enabled, activeMode)
+
+ cvh.layout.setOnClickListener { _ ->
+ cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control)
+ }
+ } else {
+ // A sub template has been specified, use this as the default behavior for user
+ // interactions (touch, range)
+ subBehavior = cvh.bindBehavior(
+ subBehavior,
+ ControlViewHolder.findBehaviorClass(
+ control.status,
+ subTemplate,
+ control.deviceType
+ ),
+ activeMode
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
index 3e16698..dc7247c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
@@ -19,7 +19,9 @@
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
+import android.service.controls.templates.TemperatureControlTemplate
import android.service.controls.templates.ToggleTemplate
+import android.util.Log
import android.view.View
import com.android.systemui.R
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
@@ -32,24 +34,31 @@
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
- cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */)
cvh.layout.setOnClickListener(View.OnClickListener() {
cvh.controlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
})
}
- override fun bind(cws: ControlWithState) {
+ override fun bind(cws: ControlWithState, colorOffset: Int) {
this.control = cws.control!!
- cvh.status.setText(control.getStatusText())
- template = control.getControlTemplate() as ToggleTemplate
+ cvh.setStatusText(control.getStatusText())
+ val controlTemplate = control.getControlTemplate()
+ template = when (controlTemplate) {
+ is ToggleTemplate -> controlTemplate
+ is TemperatureControlTemplate -> controlTemplate.getTemplate() as ToggleTemplate
+ else -> {
+ Log.e(ControlsUiController.TAG, "Unsupported template type: $controlTemplate")
+ return
+ }
+ }
val ld = cvh.layout.getBackground() as LayerDrawable
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
clipLayer.level = MAX_LEVEL
val checked = template.isChecked()
- cvh.applyRenderInfo(checked)
+ cvh.applyRenderInfo(checked, colorOffset)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 3dc0ff3..1f0ca9b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -25,11 +25,12 @@
import android.os.Bundle
import android.service.controls.Control
import android.service.controls.actions.FloatAction
+import android.service.controls.templates.ControlTemplate
import android.service.controls.templates.RangeTemplate
+import android.service.controls.templates.TemperatureControlTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.util.Log
import android.util.MathUtils
-import android.util.TypedValue
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
@@ -37,24 +38,29 @@
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
-import android.widget.TextView
import com.android.systemui.Interpolators
import com.android.systemui.R
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
import java.util.IllegalFormatException
+/**
+ * Supports [ToggleRangeTemplate] and [RangeTemplate], as well as when one of those templates is
+ * defined as the subtemplate in [TemperatureControlTemplate].
+ */
class ToggleRangeBehavior : Behavior {
private var rangeAnimator: ValueAnimator? = null
lateinit var clipLayer: Drawable
- lateinit var template: ToggleRangeTemplate
+ lateinit var templateId: String
lateinit var control: Control
lateinit var cvh: ControlViewHolder
lateinit var rangeTemplate: RangeTemplate
- lateinit var status: TextView
lateinit var context: Context
var currentStatusText: CharSequence = ""
var currentRangeValue: String = ""
+ var isChecked: Boolean = false
+ var isToggleable: Boolean = false
+ var colorOffset: Int = 0
companion object {
private const val DEFAULT_FORMAT = "%.1f"
@@ -62,10 +68,7 @@
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
- status = cvh.status
- context = status.getContext()
-
- cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */)
+ context = cvh.context
val gestureListener = ToggleRangeGestureListener(cvh.layout)
val gestureDetector = GestureDetector(context, gestureListener)
@@ -86,11 +89,42 @@
}
}
- override fun bind(cws: ControlWithState) {
+ private fun setup(template: ToggleRangeTemplate) {
+ rangeTemplate = template.getRange()
+ isToggleable = true
+ isChecked = template.isChecked()
+ }
+
+ private fun setup(template: RangeTemplate) {
+ rangeTemplate = template
+
+ // only show disabled state when value is at the minimum
+ isChecked = rangeTemplate.currentValue != rangeTemplate.minValue
+ }
+
+ private fun setupTemplate(template: ControlTemplate): Boolean {
+ return when (template) {
+ is ToggleRangeTemplate -> {
+ setup(template)
+ true
+ }
+ is RangeTemplate -> {
+ setup(template)
+ true
+ }
+ is TemperatureControlTemplate -> setupTemplate(template.getTemplate())
+ else -> {
+ Log.e(ControlsUiController.TAG, "Unsupported template type: $template")
+ false
+ }
+ }
+ }
+
+ override fun bind(cws: ControlWithState, colorOffset: Int) {
this.control = cws.control!!
+ this.colorOffset = colorOffset
currentStatusText = control.getStatusText()
- status.setText(currentStatusText)
// ControlViewHolder sets a long click listener, but we want to handle touch in
// here instead, otherwise we'll have state conflicts.
@@ -99,13 +133,14 @@
val ld = cvh.layout.getBackground() as LayerDrawable
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
- template = control.getControlTemplate() as ToggleRangeTemplate
- rangeTemplate = template.getRange()
+ val template = control.getControlTemplate()
+ if (!setupTemplate(template)) return
+ templateId = template.getTemplateId()
- val checked = template.isChecked()
- updateRange(rangeToLevelValue(rangeTemplate.currentValue), checked, /* isDragging */ false)
+ updateRange(rangeToLevelValue(rangeTemplate.currentValue), isChecked,
+ /* isDragging */ false)
- cvh.applyRenderInfo(checked)
+ cvh.applyRenderInfo(isChecked, colorOffset)
/*
* This is custom widget behavior, so add a new accessibility delegate to
@@ -141,9 +176,12 @@
): Boolean {
val handled = when (action) {
AccessibilityNodeInfo.ACTION_CLICK -> {
- cvh.controlActionCoordinator.toggle(cvh, template.getTemplateId(),
- template.isChecked())
- true
+ if (!isToggleable) {
+ false
+ } else {
+ cvh.controlActionCoordinator.toggle(cvh, templateId, isChecked)
+ true
+ }
}
AccessibilityNodeInfo.ACTION_LONG_CLICK -> {
cvh.controlActionCoordinator.longPress(cvh)
@@ -157,7 +195,7 @@
val value = arguments.getFloat(
AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
val level = rangeToLevelValue(value)
- updateRange(level, template.isChecked(), /* isDragging */ true)
+ updateRange(level, isChecked, /* isDragging */ true)
endUpdateRange()
true
}
@@ -177,12 +215,19 @@
}
fun beginUpdateRange() {
- status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
+ cvh.setStatusTextSize(context.getResources()
.getDimensionPixelSize(R.dimen.control_status_expanded).toFloat())
}
fun updateRange(level: Int, checked: Boolean, isDragging: Boolean) {
- val newLevel = if (checked) Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, level)) else MIN_LEVEL
+ val newLevel = Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, level))
+
+ // If the current level is at the minimum and the user is dragging, set the control to
+ // the enabled state to indicate their intention to enable the device. This will update
+ // control colors to support dragging.
+ if (clipLayer.level == MIN_LEVEL && newLevel > MIN_LEVEL) {
+ cvh.applyRenderInfo(checked, colorOffset, false /* animated */)
+ }
rangeAnimator?.cancel()
if (isDragging) {
@@ -209,14 +254,13 @@
val newValue = levelToRangeValue(newLevel)
currentRangeValue = format(rangeTemplate.getFormatString().toString(),
DEFAULT_FORMAT, newValue)
- val text = if (isDragging) {
- currentRangeValue
+ if (isDragging) {
+ cvh.setStatusText(currentRangeValue, /* immediately */ true)
} else {
- "$currentStatusText $currentRangeValue"
+ cvh.setStatusText("$currentStatusText $currentRangeValue")
}
- status.setText(text)
} else {
- status.setText(currentStatusText)
+ cvh.setStatusText(currentStatusText)
}
}
@@ -244,9 +288,9 @@
}
fun endUpdateRange() {
- status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
+ cvh.setStatusTextSize(context.getResources()
.getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
- status.setText("$currentStatusText $currentRangeValue")
+ cvh.setStatusText("$currentStatusText $currentRangeValue", /* immediately */ true)
cvh.action(FloatAction(rangeTemplate.getTemplateId(),
findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
}
@@ -282,7 +326,7 @@
if (isDragging) {
return
}
- cvh.controlActionCoordinator.longPress(this@ToggleRangeBehavior.cvh)
+ cvh.controlActionCoordinator.longPress(cvh)
}
override fun onScroll(
@@ -291,26 +335,21 @@
xDiff: Float,
yDiff: Float
): Boolean {
- if (!template.isChecked) {
- return false
- }
if (!isDragging) {
v.getParent().requestDisallowInterceptTouchEvent(true)
- this@ToggleRangeBehavior.beginUpdateRange()
+ beginUpdateRange()
isDragging = true
}
val ratioDiff = -xDiff / v.width
val changeAmount = ((MAX_LEVEL - MIN_LEVEL) * ratioDiff).toInt()
- this@ToggleRangeBehavior.updateRange(clipLayer.level + changeAmount,
- checked = true, isDragging = true)
+ updateRange(clipLayer.level + changeAmount, checked = true, isDragging = true)
return true
}
override fun onSingleTapUp(e: MotionEvent): Boolean {
- val th = this@ToggleRangeBehavior
- cvh.controlActionCoordinator.toggle(th.cvh, th.template.getTemplateId(),
- th.template.isChecked())
+ if (!isToggleable) return false
+ cvh.controlActionCoordinator.toggle(cvh, templateId, isChecked)
return true
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
index 7ae3df7..48f9458 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
@@ -23,6 +23,7 @@
import android.service.controls.templates.ControlTemplate
import com.android.systemui.R
+import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
/**
@@ -37,22 +38,22 @@
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
- cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */)
cvh.layout.setOnClickListener(View.OnClickListener() {
cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control)
})
}
- override fun bind(cws: ControlWithState) {
+ override fun bind(cws: ControlWithState, colorOffset: Int) {
this.control = cws.control!!
- cvh.status.setText(control.getStatusText())
+ cvh.setStatusText(control.getStatusText())
template = control.getControlTemplate()
val ld = cvh.layout.getBackground() as LayerDrawable
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
- clipLayer.setLevel(MIN_LEVEL)
- cvh.applyRenderInfo(false)
+ val enabled = if (colorOffset > 0) true else false
+ clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
+ cvh.applyRenderInfo(enabled, colorOffset)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 82ccb17..e2a6d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -21,7 +21,6 @@
import com.android.systemui.appops.AppOpsControllerImpl;
import com.android.systemui.classifier.FalsingManagerProxy;
import com.android.systemui.controls.dagger.ControlsModule;
-import com.android.systemui.doze.DozeHost;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.globalactions.GlobalActionsImpl;
import com.android.systemui.plugins.ActivityStarter;
@@ -38,7 +37,6 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
-import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -259,11 +257,6 @@
/**
*/
@Binds
- public abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost);
-
- /**
- */
- @Binds
public abstract VolumeComponent provideVolumeComponent(
VolumeDialogComponent volumeDialogComponent);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 8c572fe..3bb953a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -20,12 +20,18 @@
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
import androidx.annotation.Nullable;
import com.android.keyguard.KeyguardViewController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
+import com.android.systemui.doze.DozeHost;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
@@ -38,6 +44,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -81,10 +88,17 @@
abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager(
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
- @Binds
+ @Provides
@Singleton
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
+ static BatteryController provideBatteryController(Context context,
+ EnhancedEstimates enhancedEstimates, PowerManager powerManager,
+ BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler,
+ @Background Handler bgHandler) {
+ BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
+ broadcastDispatcher, mainHandler, bgHandler);
+ bC.init();
+ return bC;
+ }
@Binds
@Singleton
@@ -136,4 +150,7 @@
@Binds
abstract KeyguardViewController bindKeyguardViewController(
StatusBarKeyguardViewManager statusBarKeyguardViewManager);
+
+ @Binds
+ abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/LongRunning.java
similarity index 67%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
copy to packages/SystemUI/src/com/android/systemui/dagger/qualifiers/LongRunning.java
index d0f7607..e90781b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/LongRunning.java
@@ -13,12 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.UserIdInt
+package com.android.systemui.dagger.qualifiers;
-data class BubbleXmlEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String
-)
+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 LongRunning {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 8117bbb..5e36704 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -33,7 +33,6 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
@@ -59,7 +58,7 @@
private final Handler mHandler;
private final BiometricUnlockController mBiometricUnlockController;
private final BroadcastDispatcher mBroadcastDispatcher;
- private final DozeServiceHost mDozeServiceHost;
+ private final DozeHost mDozeHost;
@Inject
public DozeFactory(FalsingManager falsingManager, DozeLog dozeLog,
@@ -70,7 +69,7 @@
ProximitySensor proximitySensor,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
BiometricUnlockController biometricUnlockController,
- BroadcastDispatcher broadcastDispatcher, DozeServiceHost dozeServiceHost) {
+ BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
mFalsingManager = falsingManager;
mDozeLog = dozeLog;
mDozeParameters = dozeParameters;
@@ -86,7 +85,7 @@
mHandler = handler;
mBiometricUnlockController = biometricUnlockController;
mBroadcastDispatcher = broadcastDispatcher;
- mDozeServiceHost = dozeServiceHost;
+ mDozeHost = dozeHost;
}
/** Creates a DozeMachine with its parts for {@code dozeService}. */
@@ -95,7 +94,7 @@
WakeLock wakeLock = mDelayedWakeLockBuilder.setHandler(mHandler).setTag("Doze").build();
DozeMachine.Service wrappedService = dozeService;
- wrappedService = new DozeBrightnessHostForwarder(wrappedService, mDozeServiceHost);
+ wrappedService = new DozeBrightnessHostForwarder(wrappedService, mDozeHost);
wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
wrappedService, mDozeParameters);
wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
@@ -103,19 +102,19 @@
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager,
- mDozeServiceHost);
+ mDozeHost);
machine.setParts(new DozeMachine.Part[]{
new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
new DozeFalsingManagerAdapter(mFalsingManager),
- createDozeTriggers(dozeService, mAsyncSensorManager, mDozeServiceHost,
+ createDozeTriggers(dozeService, mAsyncSensorManager, mDozeHost,
mAlarmManager, config, mDozeParameters, mHandler, wakeLock, machine,
mDockManager, mDozeLog),
- createDozeUi(dozeService, mDozeServiceHost, wakeLock, machine, mHandler,
+ createDozeUi(dozeService, mDozeHost, wakeLock, machine, mHandler,
mAlarmManager, mDozeParameters, mDozeLog),
- new DozeScreenState(wrappedService, mHandler, mDozeServiceHost, mDozeParameters,
+ new DozeScreenState(wrappedService, mHandler, mDozeHost, mDozeParameters,
wakeLock),
createDozeScreenBrightness(dozeService, wrappedService, mAsyncSensorManager,
- mDozeServiceHost, mDozeParameters, mHandler),
+ mDozeHost, mDozeParameters, mHandler),
new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
mDozeParameters),
new DozeDockHandler(config, machine, mDockManager),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 10776c9..e1081cd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -41,6 +41,9 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -56,8 +59,8 @@
public class DozeSensors {
private static final boolean DEBUG = DozeService.DEBUG;
-
private static final String TAG = "DozeSensors";
+ private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
private final Context mContext;
private final AlarmManager mAlarmManager;
@@ -79,6 +82,23 @@
private boolean mListening;
private boolean mPaused;
+ @VisibleForTesting
+ public enum DozeSensorsUiEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "User performs pickup gesture that activates the ambient display")
+ ACTION_AMBIENT_GESTURE_PICKUP(459);
+
+ private final int mId;
+
+ DozeSensorsUiEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog) {
@@ -416,6 +436,7 @@
MetricsLogger.action(
mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
subType);
+ UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP);
}
mRegistered = false;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index cf3538c..d69c3b0 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -15,6 +15,7 @@
package com.android.systemui.globalactions;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
@@ -22,6 +23,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -68,6 +70,9 @@
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.transition.AutoTransition;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
import android.util.ArraySet;
import android.util.FeatureFlagUtils;
import android.util.Log;
@@ -120,9 +125,11 @@
import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
@@ -196,6 +203,7 @@
private final UiEventLogger mUiEventLogger;
private final NotificationShadeDepthController mDepthController;
private final BlurUtils mBlurUtils;
+ private final SysUiState mSysUiState;
// Used for RingerModeTracker
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
@@ -205,7 +213,8 @@
@VisibleForTesting
protected final ArrayList<Action> mOverflowItems = new ArrayList<>();
- private ActionsDialog mDialog;
+ @VisibleForTesting
+ protected ActionsDialog mDialog;
private Action mSilentModeAction;
private ToggleAction mAirplaneModeOn;
@@ -245,6 +254,9 @@
@UiEvent(doc = "The global actions / power menu surface became visible on the screen.")
GA_POWER_MENU_OPEN(337),
+ @UiEvent(doc = "The global actions / power menu surface was dismissed.")
+ GA_POWER_MENU_CLOSE(471),
+
@UiEvent(doc = "The global actions bugreport button was pressed.")
GA_BUGREPORT_PRESS(344),
@@ -293,7 +305,7 @@
@Background Executor backgroundExecutor,
ControlsListingController controlsListingController,
ControlsController controlsController, UiEventLogger uiEventLogger,
- RingerModeTracker ringerModeTracker, @Main Handler handler) {
+ RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler) {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -322,6 +334,7 @@
mBlurUtils = blurUtils;
mRingerModeTracker = ringerModeTracker;
mControlsController = controlsController;
+ mSysUiState = sysUiState;
mMainHandler = handler;
// receive broadcasts
@@ -359,10 +372,9 @@
@Override
public void onUnlockedChanged() {
if (mDialog != null) {
- boolean unlocked = keyguardStateController.isUnlocked()
- || keyguardStateController.canDismissLockScreen();
if (mDialog.mPanelController != null) {
- mDialog.mPanelController.onDeviceLockStateChanged(unlocked);
+ mDialog.mPanelController.onDeviceLockStateChanged(
+ !mKeyguardStateController.isUnlocked());
}
if (!mDialog.isShowingControls() && shouldShowControls()) {
mDialog.showControls(mControlsUiController);
@@ -485,6 +497,8 @@
attrs.setTitle("ActionsDialog");
attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mDialog.getWindow().setAttributes(attrs);
+ // Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports
+ mDialog.getWindow().setFlags(FLAG_ALT_FOCUSABLE_IM, FLAG_ALT_FOCUSABLE_IM);
mDialog.show();
mWindowManagerFuncs.onGlobalActionsShown();
}
@@ -629,7 +643,7 @@
ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mOverflowAdapter,
getWalletPanelViewController(), mDepthController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
- shouldShowControls() ? mControlsUiController : null, mBlurUtils,
+ shouldShowControls() ? mControlsUiController : null, mBlurUtils, mSysUiState,
shouldUseControlsLayout(), this::onRotate, mKeyguardShowing);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.setOnDismissListener(this);
@@ -1165,6 +1179,7 @@
if (mDialog == dialog) {
mDialog = null;
}
+ mUiEventLogger.log(GlobalActionsEvent.GA_POWER_MENU_CLOSE);
mWindowManagerFuncs.onGlobalActionsHidden();
mLifecycle.setCurrentState(Lifecycle.State.DESTROYED);
}
@@ -1910,6 +1925,7 @@
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final NotificationShadeDepthController mDepthController;
private final BlurUtils mBlurUtils;
+ private final SysUiState mSysUiState;
private final boolean mUseControlsLayout;
private ListPopupWindow mOverflowPopup;
private final Runnable mOnRotateCallback;
@@ -1924,7 +1940,8 @@
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
ControlsUiController controlsUiController, BlurUtils blurUtils,
- boolean useControlsLayout, Runnable onRotateCallback, boolean keyguardShowing) {
+ SysUiState sysuiState, boolean useControlsLayout, Runnable onRotateCallback,
+ boolean keyguardShowing) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
@@ -1935,6 +1952,7 @@
mNotificationShadeWindowController = notificationShadeWindowController;
mControlsUiController = controlsUiController;
mBlurUtils = blurUtils;
+ mSysUiState = sysuiState;
mUseControlsLayout = useControlsLayout;
mOnRotateCallback = onRotateCallback;
mKeyguardShowing = keyguardShowing;
@@ -2019,7 +2037,22 @@
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
- panelContainer.addView(mPanelController.getPanelContent(), panelParams);
+ View walletView = mPanelController.getPanelContent();
+ panelContainer.addView(walletView, panelParams);
+ // Smooth transitions when wallet is resized, which can happen when a card is added
+ ViewGroup root = findViewById(com.android.systemui.R.id.global_actions_grid_root);
+ if (root != null) {
+ walletView.addOnLayoutChangeListener((v, l, t, r, b, ol, ot, or, ob) -> {
+ int oldHeight = ob - ot;
+ int newHeight = b - t;
+ if (oldHeight > 0 && oldHeight != newHeight) {
+ TransitionSet transition = new AutoTransition()
+ .setDuration(250)
+ .setOrdering(TransitionSet.ORDERING_TOGETHER);
+ TransitionManager.beginDelayedTransition(root, transition);
+ }
+ });
+ }
}
}
@@ -2178,6 +2211,8 @@
mShowing = true;
mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
mNotificationShadeWindowController.setForceHasTopUi(true);
+ mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
+ .commitUpdate(mContext.getDisplayId());
ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView();
root.setOnApplyWindowInsetsListener((v, windowInsets) -> {
@@ -2196,7 +2231,7 @@
mBackgroundDrawable.setAlpha(0);
float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
ObjectAnimator alphaAnimator =
- ObjectAnimator.ofFloat(mContainer, "transitionAlpha", 0f, 1f);
+ ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f);
alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
alphaAnimator.setDuration(183);
alphaAnimator.addUpdateListener((animation) -> {
@@ -2209,8 +2244,8 @@
ObjectAnimator xAnimator =
ObjectAnimator.ofFloat(mContainer, "translationX", xOffset, 0f);
- alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- alphaAnimator.setDuration(350);
+ xAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ xAnimator.setDuration(350);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaAnimator, xAnimator);
@@ -2222,7 +2257,7 @@
dismissWithAnimation(() -> {
mContainer.setTranslationX(0);
ObjectAnimator alphaAnimator =
- ObjectAnimator.ofFloat(mContainer, "transitionAlpha", 1f, 0f);
+ ObjectAnimator.ofFloat(mContainer, "alpha", 1f, 0f);
alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
alphaAnimator.setDuration(233);
alphaAnimator.addUpdateListener((animation) -> {
@@ -2236,8 +2271,8 @@
float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
ObjectAnimator xAnimator =
ObjectAnimator.ofFloat(mContainer, "translationX", 0f, xOffset);
- alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
- alphaAnimator.setDuration(350);
+ xAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ xAnimator.setDuration(350);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaAnimator, xAnimator);
@@ -2278,6 +2313,8 @@
if (mControlsUiController != null) mControlsUiController.hide();
mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
mDepthController.updateGlobalDialogVisibility(0, null /* view */);
+ mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, false)
+ .commitUpdate(mContext.getDisplayId());
super.dismiss();
}
@@ -2337,6 +2374,14 @@
}
public void refreshDialog() {
+ // ensure dropdown menus are dismissed before re-initializing the dialog
+ dismissPanel();
+ dismissOverflow(true);
+ if (mControlsUiController != null) {
+ mControlsUiController.hide();
+ }
+
+ // re-create dialog
initializeLayout();
mGlobalActionsLayout.updateList();
if (mControlsUiController != null) {
@@ -2375,11 +2420,10 @@
@VisibleForTesting
protected boolean shouldShowControls() {
- boolean isUnlocked = mKeyguardStateController.isUnlocked()
- || mKeyguardStateController.canDismissLockScreen();
- return (isUnlocked || mShowLockScreenCardsAndControls)
+ return (mKeyguardStateController.isUnlocked() || mShowLockScreenCardsAndControls)
&& mControlsUiController.getAvailable()
- && !mControlsServiceInfos.isEmpty();
+ && !mControlsServiceInfos.isEmpty()
+ && mDeviceProvisioned;
}
// TODO: Remove legacy layout XML and classes.
protected boolean shouldUseControlsLayout() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
index c7612d4..83046ef 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.HardwareBgDrawable;
@@ -78,6 +79,31 @@
}
}
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ boolean anyTruncated = false;
+ ViewGroup listView = getListView();
+ // Check to see if any of the GlobalActionsItems have had their messages truncated
+ for (int i = 0; i < listView.getChildCount(); i++) {
+ View child = listView.getChildAt(i);
+ if (child instanceof GlobalActionsItem) {
+ GlobalActionsItem item = (GlobalActionsItem) child;
+ anyTruncated = anyTruncated || item.isTruncated();
+ }
+ }
+ // If any of the items have been truncated, set the all to single-line marquee
+ if (anyTruncated) {
+ for (int i = 0; i < listView.getChildCount(); i++) {
+ View child = listView.getChildAt(i);
+ if (child instanceof GlobalActionsItem) {
+ GlobalActionsItem item = (GlobalActionsItem) child;
+ item.setMarquee(true);
+ }
+ }
+ }
+ }
+
@VisibleForTesting
protected float getGridItemSize() {
return getContext().getResources().getDimension(R.dimen.global_actions_grid_item_height);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsItem.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsItem.java
new file mode 100644
index 0000000..07fa592
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsItem.java
@@ -0,0 +1,76 @@
+/*
+ * 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.globalactions;
+
+import android.content.Context;
+import android.text.Layout;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+/**
+ * Layout for GlobalActions items.
+ */
+public class GlobalActionsItem extends LinearLayout {
+ public GlobalActionsItem(Context context) {
+ super(context);
+ }
+
+ public GlobalActionsItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public GlobalActionsItem(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ private TextView getTextView() {
+ return (TextView) findViewById(R.id.message);
+ }
+
+ /**
+ * Sets this item to marquee or not.
+ */
+ public void setMarquee(boolean marquee) {
+ TextView text = getTextView();
+ text.setSingleLine(marquee);
+ text.setEllipsize(marquee ? TextUtils.TruncateAt.MARQUEE : TextUtils.TruncateAt.END);
+ }
+
+ /**
+ * Determines whether the message for this item has been truncated.
+ */
+ public boolean isTruncated() {
+ TextView message = getTextView();
+ if (message != null) {
+ Layout messageLayout = message.getLayout();
+ if (messageLayout != null) {
+ if (messageLayout.getLineCount() > 0) {
+ // count the number of ellipses in the last line.
+ int ellipses = messageLayout.getEllipsisCount(
+ messageLayout.getLineCount() - 1);
+ // If ellipses are present, the line was forced to truncate.
+ return ellipses > 0;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index fa45ea1..1a53c28 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
@@ -134,7 +134,7 @@
private void setupTexture(Bitmap bitmap) {
final int[] tids = new int[1];
- if (bitmap == null) {
+ if (bitmap == null || bitmap.isRecycled()) {
Log.w(TAG, "setupTexture: invalid bitmap");
return;
}
@@ -146,16 +146,20 @@
return;
}
- // Bind a named texture to a target.
- glBindTexture(GL_TEXTURE_2D, tids[0]);
- // Load the bitmap data and copy it over into the texture object that is currently bound.
- GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
- // Use bilinear texture filtering when minification.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- // Use bilinear texture filtering when magnification.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- mTextureId = tids[0];
+ try {
+ // Bind a named texture to a target.
+ glBindTexture(GL_TEXTURE_2D, tids[0]);
+ // Load the bitmap data and copy it over into the texture object
+ // that is currently bound.
+ GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
+ // Use bilinear texture filtering when minification.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ // Use bilinear texture filtering when magnification.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ mTextureId = tids[0];
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Failed uploading texture: " + e.getLocalizedMessage());
+ }
}
void useTexture() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 96494cf..3a37c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -451,7 +451,8 @@
* @param metadata New metadata.
*/
@Override
- public void onMetadataOrStateChanged(MediaMetadata metadata, @PlaybackState.State int state) {
+ public void onPrimaryMetadataOrStateChanged(MediaMetadata metadata,
+ @PlaybackState.State int state) {
synchronized (this) {
boolean nextVisible = NotificationMediaManager.isPlayingState(state);
mMediaHandler.removeCallbacksAndMessages(null);
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 123cf78..9c89fee 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -61,6 +61,18 @@
return buffer;
}
+ /** Provides a logging buffer for all logs related to managing notification sections. */
+ @Provides
+ @Singleton
+ @NotificationSectionLog
+ public static LogBuffer provideNotificationSectionLogBuffer(
+ LogcatEchoTracker bufferFilter,
+ DumpManager dumpManager) {
+ LogBuffer buffer = new LogBuffer("NotifSectionLog", 500, 10, bufferFilter);
+ buffer.attach(dumpManager);
+ return buffer;
+ }
+
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@Provides
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
new file mode 100644
index 0000000..7259eeb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
@@ -0,0 +1,33 @@
+/*
+ * 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for notification sections-related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface NotificationSectionLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/GoneChildrenHideHelper.kt b/packages/SystemUI/src/com/android/systemui/media/GoneChildrenHideHelper.kt
new file mode 100644
index 0000000..2fe0d9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/GoneChildrenHideHelper.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.media
+
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewGroup
+
+private val EMPTY_RECT = Rect(0,0,0,0)
+
+private val LAYOUT_CHANGE_LISTENER = object : View.OnLayoutChangeListener {
+
+ override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int,
+ oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
+ v?.let {
+ if (v.visibility == View.GONE) {
+ v.clipBounds = EMPTY_RECT
+ } else {
+ v.clipBounds = null
+ }
+ }
+ }
+}
+/**
+ * A helper class that clips all GONE children. Useful for transitions in motionlayout which
+ * don't clip its children.
+ */
+class GoneChildrenHideHelper private constructor() {
+ companion object {
+ @JvmStatic
+ fun clipGoneChildrenOnLayout(layout: ViewGroup) {
+ val childCount = layout.childCount
+ for (i in 0 until childCount) {
+ val child = layout.getChildAt(i)
+ child.addOnLayoutChangeListener(LAYOUT_CHANGE_LISTENER)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
new file mode 100644
index 0000000..7432165
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
@@ -0,0 +1,294 @@
+package com.android.systemui.media
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.content.res.Resources
+import android.content.res.TypedArray
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.PixelFormat
+import android.graphics.RadialGradient
+import android.graphics.Rect
+import android.graphics.Shader
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.util.MathUtils
+import android.util.MathUtils.lerp
+import android.view.MotionEvent
+import android.view.View
+import androidx.annotation.Keep
+import com.android.internal.graphics.ColorUtils
+import com.android.internal.graphics.ColorUtils.blendARGB
+import com.android.systemui.Interpolators
+import com.android.systemui.R
+import org.xmlpull.v1.XmlPullParser
+
+private const val BACKGROUND_ANIM_DURATION = 370L
+private const val RIPPLE_ANIM_DURATION = 800L
+private const val RIPPLE_DOWN_PROGRESS = 0.05f
+private const val RIPPLE_CANCEL_DURATION = 200L
+private val GRADIENT_STOPS = floatArrayOf(0.2f, 1f)
+
+private data class RippleData(
+ var x: Float,
+ var y: Float,
+ var alpha: Float,
+ var progress: Float,
+ var minSize: Float,
+ var maxSize: Float,
+ var highlight: Float
+)
+
+/**
+ * Drawable that can draw an animated gradient when tapped.
+ */
+@Keep
+class IlluminationDrawable : Drawable() {
+
+ private var themeAttrs: IntArray? = null
+ private var cornerRadius = 0f
+ private var highlightColor = Color.TRANSPARENT
+ private val rippleData = RippleData(0f, 0f, 0f, 0f, 0f, 0f, 0f)
+ private var tmpHsl = floatArrayOf(0f, 0f, 0f)
+ private var paint = Paint()
+
+ private var backgroundColor = Color.TRANSPARENT
+ set(value) {
+ if (value == field) {
+ return
+ }
+ field = value
+ animateBackground()
+ }
+
+ /**
+ * Draw a small highlight under the finger before expanding (or cancelling) it.
+ */
+ private var pressed: Boolean = false
+ set(value) {
+ if (value == field) {
+ return
+ }
+ field = value
+
+ if (value) {
+ rippleAnimation?.cancel()
+ rippleData.alpha = 1f
+ rippleData.progress = RIPPLE_DOWN_PROGRESS
+ } else {
+ rippleAnimation?.cancel()
+ rippleAnimation = ValueAnimator.ofFloat(rippleData.alpha, 0f).apply {
+ duration = RIPPLE_CANCEL_DURATION
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.alpha = it.animatedValue as Float
+ invalidateSelf()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ var cancelled = false
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true;
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ if (cancelled) {
+ return
+ }
+ rippleData.progress = 0f
+ rippleData.alpha = 0f
+ rippleAnimation = null
+ invalidateSelf()
+ }
+ })
+ start()
+ }
+ }
+ invalidateSelf()
+ }
+
+ private var rippleAnimation: Animator? = null
+ private var backgroundAnimation: ValueAnimator? = null
+
+ /**
+ * Draw background and gradient.
+ */
+ override fun draw(canvas: Canvas) {
+ paint.shader = if (rippleData.progress > 0) {
+ val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
+ val centerColor = blendARGB(paint.color, highlightColor, rippleData.alpha)
+ RadialGradient(rippleData.x, rippleData.y, radius, intArrayOf(centerColor, paint.color),
+ GRADIENT_STOPS, Shader.TileMode.CLAMP)
+ } else {
+ null
+ }
+ canvas.drawRoundRect(0f, 0f, bounds.width().toFloat(), bounds.height().toFloat(),
+ cornerRadius, cornerRadius, paint)
+ }
+
+ override fun getOpacity(): Int {
+ return PixelFormat.TRANSPARENT
+ }
+
+ override fun inflate(
+ r: Resources,
+ parser: XmlPullParser,
+ attrs: AttributeSet,
+ theme: Resources.Theme?
+ ) {
+ val a = obtainAttributes(r, theme, attrs, R.styleable.IlluminationDrawable)
+ themeAttrs = a.extractThemeAttrs()
+ updateStateFromTypedArray(a)
+ a.recycle()
+ }
+
+ private fun updateStateFromTypedArray(a: TypedArray) {
+ if (a.hasValue(R.styleable.IlluminationDrawable_cornerRadius)) {
+ cornerRadius = a.getDimension(R.styleable.IlluminationDrawable_cornerRadius,
+ cornerRadius)
+ }
+ if (a.hasValue(R.styleable.IlluminationDrawable_rippleMinSize)) {
+ rippleData.minSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMinSize, 0f)
+ }
+ if (a.hasValue(R.styleable.IlluminationDrawable_rippleMaxSize)) {
+ rippleData.maxSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMaxSize, 0f)
+ }
+ if (a.hasValue(R.styleable.IlluminationDrawable_highlight)) {
+ rippleData.highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) /
+ 100f
+ }
+ }
+
+ override fun canApplyTheme(): Boolean {
+ return themeAttrs != null && themeAttrs!!.size > 0 || super.canApplyTheme()
+ }
+
+ override fun applyTheme(t: Resources.Theme) {
+ super.applyTheme(t)
+ themeAttrs?.let {
+ val a = t.resolveAttributes(it, R.styleable.IlluminationDrawable)
+ updateStateFromTypedArray(a)
+ a.recycle()
+ }
+ }
+
+ override fun setColorFilter(p0: ColorFilter?) {
+ throw UnsupportedOperationException("Color filters are not supported")
+ }
+
+ override fun setAlpha(value: Int) {
+ throw UnsupportedOperationException("Alpha is not supported")
+ }
+
+ /**
+ * Cross fade background.
+ * @see setTintList
+ * @see backgroundColor
+ */
+ private fun animateBackground() {
+ ColorUtils.colorToHSL(backgroundColor, tmpHsl)
+ val L = tmpHsl[2]
+ tmpHsl[2] = MathUtils.constrain(if (L < 1f - rippleData.highlight) {
+ L + rippleData.highlight
+ } else {
+ L - rippleData.highlight
+ }, 0f, 1f)
+
+ val initialBackground = paint.color
+ val initialHighlight = highlightColor
+ val finalHighlight = ColorUtils.HSLToColor(tmpHsl)
+
+ backgroundAnimation?.cancel()
+ backgroundAnimation = ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = BACKGROUND_ANIM_DURATION
+ interpolator = Interpolators.FAST_OUT_LINEAR_IN
+ addUpdateListener {
+ val progress = it.animatedValue as Float
+ paint.color = blendARGB(initialBackground, backgroundColor, progress)
+ highlightColor = blendARGB(initialHighlight, finalHighlight, progress)
+ invalidateSelf()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ backgroundAnimation = null
+ }
+ })
+ start()
+ }
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ super.setTintList(tint)
+ backgroundColor = tint!!.defaultColor
+ }
+
+ /**
+ * Draws an animated ripple that expands fading away.
+ */
+ private fun illuminate() {
+ rippleData.alpha = 1f
+ invalidateSelf()
+
+ rippleAnimation?.cancel()
+ rippleAnimation = AnimatorSet().apply {
+ playTogether(ValueAnimator.ofFloat(1f, 0f).apply {
+ startDelay = 133
+ duration = RIPPLE_ANIM_DURATION - startDelay
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.alpha = it.animatedValue as Float
+ invalidateSelf()
+ }
+ }, ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
+ duration = RIPPLE_ANIM_DURATION
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.progress = it.animatedValue as Float
+ invalidateSelf()
+ }
+ })
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ rippleData.progress = 0f
+ rippleAnimation = null
+ invalidateSelf()
+ }
+ })
+ start()
+ }
+ }
+
+ /**
+ * Setup touch events on a view such as tapping it would trigger effects on this drawable.
+ * @param target View receiving touched.
+ * @param container View that holds this drawable.
+ */
+ fun setupTouch(target: View, container: View) {
+ val containerRect = Rect()
+ target.setOnTouchListener { view: View, event: MotionEvent ->
+ container.getGlobalVisibleRect(containerRect)
+ rippleData.x = event.rawX - containerRect.left
+ rippleData.y = event.rawY - containerRect.top
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ pressed = true
+ }
+ MotionEvent.ACTION_MOVE -> {
+ invalidateSelf()
+ }
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ pressed = false
+ if (event.action == MotionEvent.ACTION_UP) {
+ illuminate()
+ }
+ }
+ }
+ false
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
new file mode 100644
index 0000000..524c695
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.media
+
+import android.view.View
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.stack.MediaHeaderView
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * A class that controls the media notifications on the lock screen, handles its visibility and
+ * is responsible for the embedding of he media experience.
+ */
+@Singleton
+class KeyguardMediaController @Inject constructor(
+ private val mediaHost: MediaHost,
+ private val bypassController: KeyguardBypassController,
+ private val statusBarStateController: SysuiStatusBarStateController
+) {
+
+ init {
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onStateChanged(newState: Int) {
+ updateVisibility()
+ }
+ })
+ }
+ private var view: MediaHeaderView? = null
+
+ /**
+ * Attach this controller to a media view, initializing its state
+ */
+ fun attach(mediaView: MediaHeaderView) {
+ view = mediaView
+ // First let's set the desired state that we want for this host
+ mediaHost.visibleChangedListener = { updateVisibility() }
+ mediaHost.expansion = 0.0f
+ mediaHost.showsOnlyActiveMedia = true
+
+ // Let's now initialize this view, which also creates the host view for us.
+ mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN)
+ mediaView.setContentView(mediaHost.hostView)
+ }
+
+ private fun updateVisibility() {
+ val shouldBeVisible = mediaHost.visible
+ && !bypassController.bypassEnabled
+ && (statusBarStateController.state == StatusBarState.KEYGUARD ||
+ statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER)
+ view?.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/media/LayoutAnimationHelper.kt b/packages/SystemUI/src/com/android/systemui/media/LayoutAnimationHelper.kt
new file mode 100644
index 0000000..a366725
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/LayoutAnimationHelper.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.media
+
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver
+import com.android.systemui.statusbar.notification.AnimatableProperty
+import com.android.systemui.statusbar.notification.PropertyAnimator
+import com.android.systemui.statusbar.notification.stack.AnimationProperties
+
+/**
+ * A utility class that helps with animations of bound changes designed for motionlayout which
+ * doesn't work together with regular changeBounds.
+ */
+class LayoutAnimationHelper {
+
+ private val layout: ViewGroup
+ private var sizeAnimationPending = false
+ private val desiredBounds = mutableMapOf<View, Rect>()
+ private val animationProperties = AnimationProperties()
+ private val layoutListener = object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int,
+ oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
+ v?.let {
+ if (v.alpha == 0.0f || v.visibility == View.GONE || oldLeft - oldRight == 0 ||
+ oldTop - oldBottom == 0) {
+ return
+ }
+ if (oldLeft != left || oldTop != top || oldBottom != bottom || oldRight != right) {
+ val rect = desiredBounds.getOrPut(v, { Rect() })
+ rect.set(left, top, right, bottom)
+ onDesiredLocationChanged(v, rect)
+ }
+ }
+ }
+ }
+
+ constructor(layout: ViewGroup) {
+ this.layout = layout
+ val childCount = this.layout.childCount
+ for (i in 0 until childCount) {
+ val child = this.layout.getChildAt(i)
+ child.addOnLayoutChangeListener(layoutListener)
+ }
+ }
+
+ private fun onDesiredLocationChanged(v: View, rect: Rect) {
+ if (!sizeAnimationPending) {
+ applyBounds(v, rect, animate = false)
+ }
+ // We need to reapply the current bounds in every frame since the layout may override
+ // the layout bounds making this view jump and not all calls to apply bounds actually
+ // reapply them, for example if there's already an animator to the same target
+ reapplyProperty(v, AnimatableProperty.ABSOLUTE_X);
+ reapplyProperty(v, AnimatableProperty.ABSOLUTE_Y);
+ reapplyProperty(v, AnimatableProperty.WIDTH);
+ reapplyProperty(v, AnimatableProperty.HEIGHT);
+ }
+
+ private fun reapplyProperty(v: View, property: AnimatableProperty) {
+ property.property.set(v, property.property.get(v))
+ }
+
+ private fun applyBounds(v: View, newBounds: Rect, animate: Boolean) {
+ PropertyAnimator.setProperty(v, AnimatableProperty.ABSOLUTE_X, newBounds.left.toFloat(),
+ animationProperties, animate)
+ PropertyAnimator.setProperty(v, AnimatableProperty.ABSOLUTE_Y, newBounds.top.toFloat(),
+ animationProperties, animate)
+ PropertyAnimator.setProperty(v, AnimatableProperty.WIDTH, newBounds.width().toFloat(),
+ animationProperties, animate)
+ PropertyAnimator.setProperty(v, AnimatableProperty.HEIGHT, newBounds.height().toFloat(),
+ animationProperties, animate)
+ }
+
+ private fun startBoundAnimation(v: View) {
+ val target = desiredBounds[v] ?: return
+ applyBounds(v, target, animate = true)
+ }
+
+ fun animatePendingSizeChange(duration: Long, delay: Long) {
+ animationProperties.duration = duration
+ animationProperties.delay = delay
+ if (!sizeAnimationPending) {
+ sizeAnimationPending = true
+ layout.viewTreeObserver.addOnPreDrawListener (
+ object : ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ layout.viewTreeObserver.removeOnPreDrawListener(this)
+ sizeAnimationPending = false
+ val childCount = layout.childCount
+ for (i in 0 until childCount) {
+ val child = layout.getChildAt(i)
+ startBoundAnimation(child)
+ }
+ return true
+ }
+ })
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 557132b..1691c53 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -16,10 +16,8 @@
package com.android.systemui.media;
-import android.annotation.LayoutRes;
import android.app.PendingIntent;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -27,35 +25,37 @@
import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
-import android.graphics.ImageDecoder;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.RippleDrawable;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.ThumbnailUtils;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
-import android.net.Uri;
import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+import androidx.constraintlayout.motion.widget.Key;
+import androidx.constraintlayout.motion.widget.KeyAttributes;
+import androidx.constraintlayout.motion.widget.KeyFrames;
+import androidx.constraintlayout.motion.widget.MotionLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import com.android.settingslib.Utils;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputSliceConstants;
@@ -64,34 +64,50 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSMediaBrowser;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.concurrency.DelayableExecutor;
-import java.io.IOException;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
/**
- * Base media control panel for System UI
+ * A view controller used for Media Playback.
*/
public class MediaControlPanel {
private static final String TAG = "MediaControlPanel";
@Nullable private final LocalMediaManager mLocalMediaManager;
+
+ // Button IDs for QS controls
+ static final int[] ACTION_IDS = {
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4
+ };
+
+ private final SeekBarViewModel mSeekBarViewModel;
+ private SeekBarObserver mSeekBarObserver;
private final Executor mForegroundExecutor;
protected final Executor mBackgroundExecutor;
private final ActivityStarter mActivityStarter;
+ private LayoutAnimationHelper mLayoutAnimationHelper;
private Context mContext;
- protected LinearLayout mMediaNotifView;
- private View mSeamless;
+ private PlayerViewHolder mViewHolder;
private MediaSession.Token mToken;
private MediaController mController;
- private int mForegroundColor;
private int mBackgroundColor;
private MediaDevice mDevice;
protected ComponentName mServiceComponent;
private boolean mIsRegistered = false;
+ private List<KeyFrames> mKeyFrames;
private String mKey;
-
- private final int[] mActionIds;
+ private int mAlbumArtSize;
+ private int mAlbumArtRadius;
+ private int mViewWidth;
public static final String MEDIA_PREFERENCES = "media_control_prefs";
public static final String MEDIA_PREFERENCE_KEY = "browser_components";
@@ -100,22 +116,6 @@
private boolean mIsRemotePlayback;
private QSMediaBrowser mQSMediaBrowser;
- // Button IDs used in notifications
- protected static final int[] NOTIF_ACTION_IDS = {
- com.android.internal.R.id.action0,
- com.android.internal.R.id.action1,
- com.android.internal.R.id.action2,
- com.android.internal.R.id.action3,
- com.android.internal.R.id.action4
- };
-
- // URI fields to try loading album art from
- private static final String[] ART_URIS = {
- MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
- MediaMetadata.METADATA_KEY_ART_URI,
- MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
- };
-
private final MediaController.Callback mSessionCallback = new MediaController.Callback() {
@Override
public void onSessionDestroyed() {
@@ -135,17 +135,6 @@
}
};
- private final OnAttachStateChangeListener mStateListener = new OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View unused) {
- makeActive();
- }
- @Override
- public void onViewDetachedFromWindow(View unused) {
- makeInactive();
- }
- };
-
private final LocalMediaManager.DeviceCallback mDeviceCallback =
new LocalMediaManager.DeviceCallback() {
@Override
@@ -173,40 +162,55 @@
/**
* Initialize a new control panel
* @param context
- * @param parent
* @param routeManager Manager used to listen for device change events.
- * @param layoutId layout resource to use for this control panel
- * @param actionIds resource IDs for action buttons in the layout
* @param foregroundExecutor foreground executor
* @param backgroundExecutor background executor, used for processing artwork
* @param activityStarter activity starter
*/
- public MediaControlPanel(Context context, ViewGroup parent,
- @Nullable LocalMediaManager routeManager, @LayoutRes int layoutId, int[] actionIds,
- Executor foregroundExecutor, Executor backgroundExecutor,
+ public MediaControlPanel(Context context, @Nullable LocalMediaManager routeManager,
+ Executor foregroundExecutor, DelayableExecutor backgroundExecutor,
ActivityStarter activityStarter) {
mContext = context;
- LayoutInflater inflater = LayoutInflater.from(mContext);
- mMediaNotifView = (LinearLayout) inflater.inflate(layoutId, parent, false);
- // TODO(b/150854549): removeOnAttachStateChangeListener when this doesn't inflate views
- // mStateListener shouldn't need to be unregistered since this object shares the same
- // lifecycle with the inflated view. It would be better, however, if this controller used an
- // attach/detach of views instead of inflating them in the constructor, which would allow
- // mStateListener to be unregistered in detach.
- mMediaNotifView.addOnAttachStateChangeListener(mStateListener);
mLocalMediaManager = routeManager;
- mActionIds = actionIds;
mForegroundExecutor = foregroundExecutor;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
+ mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor);
+ loadDimens();
+ }
+
+ public void onDestroy() {
+ if (mSeekBarObserver != null) {
+ mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver);
+ }
+ makeInactive();
+ }
+
+ private void loadDimens() {
+ mAlbumArtRadius = mContext.getResources().getDimensionPixelSize(
+ Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ mAlbumArtSize = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_album_size);
}
/**
- * Get the view used to display media controls
- * @return the view
+ * Get the view holder used to display media controls
+ * @return the view holder
*/
- public View getView() {
- return mMediaNotifView;
+ @Nullable
+ public PlayerViewHolder getView() {
+ return mViewHolder;
+ }
+
+ /**
+ * Sets the listening state of the player.
+ *
+ * Should be set to true when the QS panel is open. Otherwise, false. This is a signal to avoid
+ * unnecessary work when the QS panel is closed.
+ *
+ * @param listening True when player should be active. Otherwise, false.
+ */
+ public void setListening(boolean listening) {
+ mSeekBarViewModel.setListening(listening);
}
/**
@@ -217,21 +221,29 @@
return mContext;
}
+ /** Attaches the player to the view holder. */
+ public void attach(PlayerViewHolder vh) {
+ mViewHolder = vh;
+ MotionLayout motionView = vh.getPlayer();
+ mLayoutAnimationHelper = new LayoutAnimationHelper(motionView);
+ GoneChildrenHideHelper.clipGoneChildrenOnLayout(motionView);
+ mKeyFrames = motionView.getDefinedTransitions().get(0).getKeyFrameList();
+ mSeekBarObserver = new SeekBarObserver(motionView);
+ mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
+ SeekBar bar = vh.getSeekBar();
+ bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener());
+ bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener());
+ }
+
/**
- * Update the media panel view for the given media session
- * @param token
- * @param iconDrawable
- * @param largeIcon
- * @param iconColor
- * @param bgColor
- * @param contentIntent
- * @param appNameString
- * @param key
+ * Bind this view based on the data given
*/
- public void setMediaSession(MediaSession.Token token, Drawable iconDrawable, Icon largeIcon,
- int iconColor, int bgColor, PendingIntent contentIntent, String appNameString,
- String key) {
- // Ensure that component names are updated if token has changed
+ public void bind(@NotNull MediaData data) {
+ if (mViewHolder == null) {
+ return;
+ }
+ MediaSession.Token token = data.getToken();
+ mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
if (mQSMediaBrowser != null) {
Log.d(TAG, "Disconnecting old media browser");
@@ -243,20 +255,21 @@
mCheckedForResumption = false;
}
- mForegroundColor = iconColor;
- mBackgroundColor = bgColor;
mController = new MediaController(mContext, mToken);
- mKey = key;
+
+ ConstraintSet expandedSet = mViewHolder.getPlayer().getConstraintSet(R.id.expanded);
+ ConstraintSet collapsedSet = mViewHolder.getPlayer().getConstraintSet(R.id.collapsed);
// Try to find a browser service component for this app
// TODO also check for a media button receiver intended for restarting (b/154127084)
// Only check if we haven't tried yet or the session token changed
- final String pkgName = mController.getPackageName();
+ final String pkgName = data.getPackageName();
if (mServiceComponent == null && !mCheckedForResumption) {
Log.d(TAG, "Checking for service component");
PackageManager pm = mContext.getPackageManager();
Intent resumeIntent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
List<ResolveInfo> resumeInfo = pm.queryIntentServices(resumeIntent, 0);
+ // TODO: look into this resumption
if (resumeInfo != null) {
for (ResolveInfo inf : resumeInfo) {
if (inf.serviceInfo.packageName.equals(mController.getPackageName())) {
@@ -271,38 +284,56 @@
mController.registerCallback(mSessionCallback);
- mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
+ mViewHolder.getBackground().setBackgroundTintList(
+ ColorStateList.valueOf(mBackgroundColor));
// Click action
- if (contentIntent != null) {
- mMediaNotifView.setOnClickListener(v -> {
- mActivityStarter.postStartActivityDismissingKeyguard(contentIntent);
+ PendingIntent clickIntent = data.getClickIntent();
+ if (clickIntent != null) {
+ mViewHolder.getPlayer().setOnClickListener(v -> {
+ mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
});
}
+ ImageView albumView = mViewHolder.getAlbumView();
+ // TODO: migrate this to a view with rounded corners instead of baking the rounding
+ // into the bitmap
+ Drawable artwork = createRoundedBitmap(data.getArtwork());
+ albumView.setImageDrawable(artwork);
+
// App icon
- ImageView appIcon = mMediaNotifView.findViewById(R.id.icon);
- iconDrawable.setTint(mForegroundColor);
- appIcon.setImageDrawable(iconDrawable);
+ ImageView appIcon = mViewHolder.getAppIcon();
+ appIcon.setImageDrawable(data.getAppIcon());
+
+ // Song name
+ TextView titleText = mViewHolder.getTitleText();
+ titleText.setText(data.getSong());
+
+ // App title
+ TextView appName = mViewHolder.getAppName();
+ appName.setText(data.getApp());
+
+ // Artist name
+ TextView artistText = mViewHolder.getArtistText();
+ artistText.setText(data.getArtist());
// Transfer chip
- mSeamless = mMediaNotifView.findViewById(R.id.media_seamless);
- if (mSeamless != null) {
- if (mLocalMediaManager != null) {
- mSeamless.setVisibility(View.VISIBLE);
- updateDevice(mLocalMediaManager.getCurrentConnectedDevice());
- mSeamless.setOnClickListener(v -> {
- final Intent intent = new Intent()
- .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
- .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
- mController.getPackageName())
- .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
- mActivityStarter.startActivity(intent, false, true /* dismissShade */,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- });
- } else {
- Log.d(TAG, "LocalMediaManager is null. Not binding output chip for pkg=" + pkgName);
- }
+ if (mLocalMediaManager != null) {
+ mViewHolder.getSeamless().setVisibility(View.VISIBLE);
+ setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
+ setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
+ updateDevice(mLocalMediaManager.getCurrentConnectedDevice());
+ mViewHolder.getSeamless().setOnClickListener(v -> {
+ final Intent intent = new Intent()
+ .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+ .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+ mController.getPackageName())
+ .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
+ mActivityStarter.startActivity(intent, false, true /* dismissShade */,
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ });
+ } else {
+ Log.d(TAG, "LocalMediaManager is null. Not binding output chip for pkg=" + pkgName);
}
PlaybackInfo playbackInfo = mController.getPlaybackInfo();
if (playbackInfo != null) {
@@ -311,43 +342,106 @@
Log.d(TAG, "PlaybackInfo was null. Defaulting to local playback.");
mIsRemotePlayback = false;
}
+ List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
+ // Media controls
+ int i = 0;
+ List<MediaAction> actionIcons = data.getActions();
+ for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) {
+ int actionId = ACTION_IDS[i];
+ final ImageButton button = mViewHolder.getAction(actionId);
+ MediaAction mediaAction = actionIcons.get(i);
+ button.setImageDrawable(mediaAction.getDrawable());
+ button.setContentDescription(mediaAction.getContentDescription());
+ PendingIntent actionIntent = mediaAction.getIntent();
+
+ button.setOnClickListener(v -> {
+ if (actionIntent != null) {
+ try {
+ actionIntent.send();
+ } catch (PendingIntent.CanceledException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ boolean visibleInCompat = actionsWhenCollapsed.contains(i);
+ updateKeyFrameVisibility(actionId, visibleInCompat);
+ setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
+ setVisibleAndAlpha(expandedSet, actionId, true /*visible */);
+ }
+
+ // Hide any unused buttons
+ for (; i < ACTION_IDS.length; i++) {
+ setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
+ setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
+ }
+
+ // Seek Bar
+ final MediaController controller = getController();
+ mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
+
+ // Set up long press menu
+ // TODO: b/156036025 bring back media guts
makeActive();
- // App title (not in mini player)
- TextView appName = mMediaNotifView.findViewById(R.id.app_name);
- if (appName != null) {
- appName.setText(appNameString);
- appName.setTextColor(mForegroundColor);
+ // Update both constraint sets to regenerate the animation.
+ mViewHolder.getPlayer().updateState(R.id.collapsed, collapsedSet);
+ mViewHolder.getPlayer().updateState(R.id.expanded, expandedSet);
+ }
+
+ @UiThread
+ private Drawable createRoundedBitmap(Icon icon) {
+ if (icon == null) {
+ return null;
}
-
- // Can be null!
- MediaMetadata mediaMetadata = mController.getMetadata();
-
- ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
- if (albumView != null) {
- // Resize art in a background thread
- mBackgroundExecutor.execute(() -> processAlbumArt(mediaMetadata, largeIcon, albumView));
+ // Let's scale down the View, such that the content always nicely fills the view.
+ // ThumbnailUtils actually scales it down such that it may not be filled for odd aspect
+ // ratios
+ Drawable drawable = icon.loadDrawable(mContext);
+ float aspectRatio = drawable.getIntrinsicHeight() / (float) drawable.getIntrinsicWidth();
+ Rect bounds;
+ if (aspectRatio > 1.0f) {
+ bounds = new Rect(0, 0, mAlbumArtSize, (int) (mAlbumArtSize * aspectRatio));
+ } else {
+ bounds = new Rect(0, 0, (int) (mAlbumArtSize / aspectRatio), mAlbumArtSize);
}
-
- // Song name
- TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
- String songName = "";
- if (mediaMetadata != null) {
- songName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ if (bounds.width() > mAlbumArtSize || bounds.height() > mAlbumArtSize) {
+ float offsetX = (bounds.width() - mAlbumArtSize) / 2.0f;
+ float offsetY = (bounds.height() - mAlbumArtSize) / 2.0f;
+ bounds.offset((int) -offsetX,(int) -offsetY);
}
- titleText.setText(songName);
- titleText.setTextColor(mForegroundColor);
+ drawable.setBounds(bounds);
+ Bitmap scaled = Bitmap.createBitmap(mAlbumArtSize, mAlbumArtSize,
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(scaled);
+ drawable.draw(canvas);
+ RoundedBitmapDrawable artwork = RoundedBitmapDrawableFactory.create(
+ mContext.getResources(), scaled);
+ artwork.setCornerRadius(mAlbumArtRadius);
+ return artwork;
+ }
- // Artist name (not in mini player)
- TextView artistText = mMediaNotifView.findViewById(R.id.header_artist);
- if (artistText != null) {
- String artistName = "";
- if (mediaMetadata != null) {
- artistName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+ /**
+ * Updates the keyframe visibility such that only views that are not visible actually go
+ * through a transition and fade in.
+ *
+ * @param actionId the id to change
+ * @param visible is the view visible
+ */
+ private void updateKeyFrameVisibility(int actionId, boolean visible) {
+ if (mKeyFrames == null) {
+ return;
+ }
+ for (int i = 0; i < mKeyFrames.size(); i++) {
+ KeyFrames keyframe = mKeyFrames.get(i);
+ ArrayList<Key> viewKeyFrames = keyframe.getKeyFramesForView(actionId);
+ for (int j = 0; j < viewKeyFrames.size(); j++) {
+ Key key = viewKeyFrames.get(j);
+ if (key instanceof KeyAttributes) {
+ KeyAttributes attributes = (KeyAttributes) key;
+ attributes.setValue("alpha", visible ? 1.0f : 0.0f);
+ }
}
- artistText.setText(artistName);
- artistText.setTextColor(mForegroundColor);
}
}
@@ -421,159 +515,40 @@
}
/**
- * Process album art for layout
- * @param description media description
- * @param albumView view to hold the album art
- */
- protected void processAlbumArt(MediaDescription description, ImageView albumView) {
- Bitmap albumArt = null;
-
- // First try loading from URI
- albumArt = loadBitmapFromUri(description.getIconUri());
-
- // Then check bitmap
- if (albumArt == null) {
- albumArt = description.getIconBitmap();
- }
-
- processAlbumArtInternal(albumArt, albumView);
- }
-
- /**
- * Process album art for layout
- * @param metadata media metadata
- * @param largeIcon from notification, checked as a fallback if metadata does not have art
- * @param albumView view to hold the album art
- */
- private void processAlbumArt(MediaMetadata metadata, Icon largeIcon, ImageView albumView) {
- Bitmap albumArt = null;
-
- if (metadata != null) {
- // First look in URI fields
- for (String field : ART_URIS) {
- String uriString = metadata.getString(field);
- if (!TextUtils.isEmpty(uriString)) {
- albumArt = loadBitmapFromUri(Uri.parse(uriString));
- if (albumArt != null) {
- Log.d(TAG, "loaded art from " + field);
- break;
- }
- }
- }
-
- // Then check bitmap field
- if (albumArt == null) {
- albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- }
- }
-
- // Finally try the notification's largeIcon
- if (albumArt == null && largeIcon != null) {
- albumArt = largeIcon.getBitmap();
- }
-
- processAlbumArtInternal(albumArt, albumView);
- }
-
- /**
- * Load a bitmap from a URI
- * @param uri
- * @return bitmap, or null if couldn't be loaded
- */
- private Bitmap loadBitmapFromUri(Uri uri) {
- // ImageDecoder requires a scheme of the following types
- if (uri.getScheme() == null) {
- return null;
- }
-
- if (!uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
- && !uri.getScheme().equals(ContentResolver.SCHEME_ANDROID_RESOURCE)
- && !uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
- return null;
- }
-
- ImageDecoder.Source source = ImageDecoder.createSource(mContext.getContentResolver(), uri);
- try {
- return ImageDecoder.decodeBitmap(source);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
-
- /**
- * Resize and crop the image if provided and update the control view
- * @param albumArt Bitmap of art to display, or null to hide view
- * @param albumView View that will hold the art
- */
- private void processAlbumArtInternal(@Nullable Bitmap albumArt, ImageView albumView) {
- // Resize
- RoundedBitmapDrawable roundedDrawable = null;
- if (albumArt != null) {
- float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
- Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
- int albumSize = (int) mContext.getResources().getDimension(
- R.dimen.qs_media_album_size);
- Bitmap scaled = ThumbnailUtils.extractThumbnail(original, albumSize, albumSize);
- roundedDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
- roundedDrawable.setCornerRadius(radius);
- } else {
- Log.e(TAG, "No album art available");
- }
-
- // Now that it's resized, update the UI
- final RoundedBitmapDrawable result = roundedDrawable;
- mForegroundExecutor.execute(() -> {
- if (result != null) {
- albumView.setImageDrawable(result);
- albumView.setVisibility(View.VISIBLE);
- } else {
- albumView.setImageDrawable(null);
- albumView.setVisibility(View.GONE);
- }
- });
- }
-
- /**
* Update the current device information
* @param device device information to display
*/
private void updateDevice(MediaDevice device) {
- if (mSeamless == null) {
- return;
- }
mForegroundExecutor.execute(() -> {
updateChipInternal(device);
});
}
private void updateChipInternal(MediaDevice device) {
- ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor);
+ if (mViewHolder == null) {
+ return;
+ }
+ ImageView iconView = mViewHolder.getSeamlessIcon();
+ TextView deviceName = mViewHolder.getSeamlessText();
// Update the outline color
- LinearLayout viewLayout = (LinearLayout) mSeamless;
+ LinearLayout viewLayout = (LinearLayout) mViewHolder.getSeamless();
RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
- rect.setStroke(2, mForegroundColor);
- rect.setColor(mBackgroundColor);
-
- ImageView iconView = mSeamless.findViewById(R.id.media_seamless_image);
- TextView deviceName = mSeamless.findViewById(R.id.media_seamless_text);
- deviceName.setTextColor(fgTintList);
+ rect.setStroke(2, deviceName.getCurrentTextColor());
+ rect.setColor(Color.TRANSPARENT);
if (mIsRemotePlayback) {
- mSeamless.setEnabled(false);
- mSeamless.setAlpha(0.38f);
+ mViewHolder.getSeamless().setEnabled(false);
+ mViewHolder.getSeamless().setAlpha(0.38f);
iconView.setImageResource(R.drawable.ic_hardware_speaker);
iconView.setVisibility(View.VISIBLE);
- iconView.setImageTintList(fgTintList);
deviceName.setText(R.string.media_seamless_remote_device);
} else if (device != null) {
- mSeamless.setEnabled(true);
- mSeamless.setAlpha(1f);
+ mViewHolder.getSeamless().setEnabled(true);
+ mViewHolder.getSeamless().setAlpha(1f);
Drawable icon = device.getIcon();
iconView.setVisibility(View.VISIBLE);
- iconView.setImageTintList(fgTintList);
if (icon instanceof AdaptiveIcon) {
AdaptiveIcon aIcon = (AdaptiveIcon) icon;
@@ -586,8 +561,8 @@
} else {
// Reset to default
Log.d(TAG, "device is null. Not binding output chip.");
- mSeamless.setEnabled(true);
- mSeamless.setAlpha(1f);
+ mViewHolder.getSeamless().setEnabled(true);
+ mViewHolder.getSeamless().setAlpha(1f);
iconView.setVisibility(View.GONE);
deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
}
@@ -612,16 +587,20 @@
* Hide the media buttons and show only a restart button
*/
protected void resetButtons() {
+ if (mViewHolder == null) {
+ return;
+ }
// Hide all the old buttons
- for (int i = 0; i < mActionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(mActionIds[i]);
- if (thisBtn != null) {
- thisBtn.setVisibility(View.GONE);
- }
+
+ ConstraintSet expandedSet = mViewHolder.getPlayer().getConstraintSet(R.id.expanded);
+ ConstraintSet collapsedSet = mViewHolder.getPlayer().getConstraintSet(R.id.collapsed);
+ for (int i = 1; i < ACTION_IDS.length; i++) {
+ setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
+ setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
}
// Add a restart button
- ImageButton btn = mMediaNotifView.findViewById(mActionIds[0]);
+ ImageButton btn = mViewHolder.getAction0();
btn.setOnClickListener(v -> {
Log.d(TAG, "Attempting to restart session");
if (mQSMediaBrowser != null) {
@@ -642,8 +621,25 @@
mQSMediaBrowser.restart();
});
btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
- btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
- btn.setVisibility(View.VISIBLE);
+ setVisibleAndAlpha(expandedSet, ACTION_IDS[0], true /*visible */);
+ setVisibleAndAlpha(collapsedSet, ACTION_IDS[0], true /*visible */);
+
+ mSeekBarViewModel.clearController();
+ // TODO: fix guts
+ // View guts = mMediaNotifView.findViewById(R.id.media_guts);
+ View options = mViewHolder.getOptions();
+
+ mViewHolder.getPlayer().setOnLongClickListener(v -> {
+ // Replace player view with close/cancel view
+// guts.setVisibility(View.GONE);
+ options.setVisibility(View.VISIBLE);
+ return true; // consumed click
+ });
+ }
+
+ private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
+ set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
+ set.setAlpha(actionId, visible ? 1.0f : 0.0f);
}
private void makeActive() {
@@ -667,7 +663,6 @@
mIsRegistered = false;
}
}
-
/**
* Verify that we can connect to the given component with a MediaBrowser, and if so, add that
* component to the list of resumption components
@@ -739,4 +734,33 @@
* Called when a player can't be resumed to give it an opportunity to hide or remove itself
*/
protected void removePlayer() { }
+
+ public void measure(@Nullable MediaMeasurementInput input) {
+ if (mViewHolder == null) {
+ return;
+ }
+ if (input != null) {
+ int width = input.getWidth();
+ setPlayerWidth(width);
+ mViewHolder.getPlayer().measure(input.getWidthMeasureSpec(),
+ input.getHeightMeasureSpec());
+ }
+ }
+
+ public void setPlayerWidth(int width) {
+ if (mViewHolder == null) {
+ return;
+ }
+ MotionLayout view = mViewHolder.getPlayer();
+ ConstraintSet expandedSet = view.getConstraintSet(R.id.expanded);
+ ConstraintSet collapsedSet = view.getConstraintSet(R.id.collapsed);
+ collapsedSet.setGuidelineBegin(R.id.view_width, width);
+ expandedSet.setGuidelineBegin(R.id.view_width, width);
+ view.updateState(R.id.collapsed, collapsedSet);
+ view.updateState(R.id.expanded, expandedSet);
+ }
+
+ public void animatePendingSizeChange(long duration, long startDelay) {
+ mLayoutAnimationHelper.animatePendingSizeChange(duration, startDelay);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
new file mode 100644
index 0000000..85965d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.media
+
+import android.app.PendingIntent
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.media.session.MediaSession
+
+/** State of a media view. */
+data class MediaData(
+ val initialized: Boolean = false,
+ val backgroundColor: Int,
+ val app: String?,
+ val appIcon: Drawable?,
+ val artist: CharSequence?,
+ val song: CharSequence?,
+ val artwork: Icon?,
+ val actions: List<MediaAction>,
+ val actionsToShowInCompact: List<Int>,
+ val packageName: String?,
+ val token: MediaSession.Token?,
+ val clickIntent: PendingIntent?
+)
+
+/** State of a media action. */
+data class MediaAction(
+ val drawable: Drawable?,
+ val intent: PendingIntent?,
+ val contentDescription: CharSequence?
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
new file mode 100644
index 0000000..90c558a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -0,0 +1,310 @@
+/*
+ * 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.media
+
+import android.app.Notification
+import android.content.ContentResolver
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ImageDecoder
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.media.MediaMetadata
+import android.media.session.MediaSession
+import android.net.Uri
+import android.service.notification.StatusBarNotification
+import android.text.TextUtils
+import android.util.Log
+import com.android.internal.graphics.ColorUtils
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.notification.MediaNotificationProcessor
+import com.android.systemui.statusbar.notification.row.HybridGroupManager
+import com.android.systemui.util.Utils
+import java.io.IOException
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+
+// URI fields to try loading album art from
+private val ART_URIS = arrayOf(
+ MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
+ MediaMetadata.METADATA_KEY_ART_URI,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
+)
+
+private const val TAG = "MediaDataManager"
+private const val DEFAULT_LUMINOSITY = 0.25f
+private const val LUMINOSITY_THRESHOLD = 0.05f
+private const val SATURATION_MULTIPLIER = 0.8f
+
+private val LOADING = MediaData(false, 0, null, null, null, null, null,
+ emptyList(), emptyList(), null, null, null)
+
+/**
+ * A class that facilitates management and loading of Media Data, ready for binding.
+ */
+@Singleton
+class MediaDataManager @Inject constructor(
+ private val context: Context,
+ private val mediaControllerFactory: MediaControllerFactory,
+ @Background private val backgroundExecutor: Executor,
+ @Main private val foregroundExcecutor: Executor
+) {
+
+ private val listeners: MutableSet<Listener> = mutableSetOf()
+ private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
+
+ fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
+ if (isMediaNotification(sbn)) {
+ if (!mediaEntries.containsKey(key)) {
+ mediaEntries.put(key, LOADING)
+ }
+ loadMediaData(key, sbn)
+ } else {
+ onNotificationRemoved(key)
+ }
+ }
+
+ private fun loadMediaData(key: String, sbn: StatusBarNotification) {
+ backgroundExecutor.execute {
+ loadMediaDataInBg(key, sbn)
+ }
+ }
+
+ /**
+ * Add a listener for changes in this class
+ */
+ fun addListener(listener: Listener) = listeners.add(listener)
+
+ /**
+ * Remove a listener for changes in this class
+ */
+ fun removeListener(listener: Listener) = listeners.remove(listener)
+
+ private fun loadMediaDataInBg(key: String, sbn: StatusBarNotification) {
+ val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
+ as MediaSession.Token?
+ val metadata = mediaControllerFactory.create(token).metadata
+
+ if (metadata == null) {
+ // TODO: handle this better, removing media notification
+ return
+ }
+
+ // Foreground and Background colors computed from album art
+ val notif: Notification = sbn.notification
+ var bgColor = Color.WHITE
+ var artworkBitmap = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART)
+ if (artworkBitmap == null) {
+ artworkBitmap = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
+ }
+ if (artworkBitmap == null) {
+ artworkBitmap = loadBitmapFromUri(metadata)
+ }
+ val artWorkIcon = if (artworkBitmap == null) {
+ notif.getLargeIcon()
+ } else {
+ Icon.createWithBitmap(artworkBitmap)
+ }
+ if (artWorkIcon != null) {
+ // If we have art, get colors from that
+ if (artworkBitmap == null) {
+ if (artWorkIcon.type == Icon.TYPE_BITMAP ||
+ artWorkIcon.type == Icon.TYPE_ADAPTIVE_BITMAP) {
+ artworkBitmap = artWorkIcon.bitmap
+ } else {
+ val drawable: Drawable = artWorkIcon.loadDrawable(context)
+ artworkBitmap = Bitmap.createBitmap(
+ drawable.intrinsicWidth,
+ drawable.intrinsicHeight,
+ Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(artworkBitmap)
+ drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
+ drawable.draw(canvas)
+ }
+ }
+ val p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
+ .generate()
+ val swatch = MediaNotificationProcessor.findBackgroundSwatch(p)
+ bgColor = swatch.rgb
+ }
+ // Adapt background color, so it's always subdued and text is legible
+ val tmpHsl = floatArrayOf(0f, 0f, 0f)
+ ColorUtils.colorToHSL(bgColor, tmpHsl)
+
+ val l = tmpHsl[2]
+ // Colors with very low luminosity can have any saturation. This means that changing the
+ // luminosity can make a black become red. Let's remove the saturation of very light or
+ // very dark colors to avoid this issue.
+ if (l < LUMINOSITY_THRESHOLD || l > 1f - LUMINOSITY_THRESHOLD) {
+ tmpHsl[1] = 0f
+ }
+ tmpHsl[1] *= SATURATION_MULTIPLIER
+ tmpHsl[2] = DEFAULT_LUMINOSITY
+
+ bgColor = ColorUtils.HSLToColor(tmpHsl)
+
+ // App name
+ val builder = Notification.Builder.recoverBuilder(context, notif)
+ val app = builder.loadHeaderAppName()
+
+ // App Icon
+ val smallIconDrawable: Drawable = sbn.notification.smallIcon.loadDrawable(context)
+
+ // Song name
+ var song: CharSequence? = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
+ if (song == null) {
+ song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE)
+ }
+ if (song == null) {
+ song = HybridGroupManager.resolveTitle(notif)
+ }
+
+ // Artist name
+ var artist: CharSequence? = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)
+ if (artist == null) {
+ artist = HybridGroupManager.resolveText(notif)
+ }
+
+ // Control buttons
+ val actionIcons: MutableList<MediaAction> = ArrayList()
+ val actions = notif.actions
+ val actionsToShowCollapsed = notif.extras.getIntArray(
+ Notification.EXTRA_COMPACT_ACTIONS)?.toList() ?: emptyList()
+ // TODO: b/153736623 look into creating actions when this isn't a media style notification
+
+ val packageContext: Context = sbn.getPackageContext(context)
+ if (actions != null) {
+ for (action in actions) {
+ val mediaAction = MediaAction(
+ action.getIcon().loadDrawable(packageContext),
+ action.actionIntent,
+ action.title)
+ actionIcons.add(mediaAction)
+ }
+ }
+
+ foregroundExcecutor.execute {
+ onMediaDataLoaded(key, MediaData(true, bgColor, app, smallIconDrawable, artist, song,
+ artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
+ notif.contentIntent))
+ }
+ }
+
+ /**
+ * Load a bitmap from the various Art metadata URIs
+ */
+ private fun loadBitmapFromUri(metadata: MediaMetadata): Bitmap? {
+ for (uri in ART_URIS) {
+ val uriString = metadata.getString(uri)
+ if (!TextUtils.isEmpty(uriString)) {
+ val albumArt = loadBitmapFromUri(Uri.parse(uriString))
+ if (albumArt != null) {
+ Log.d(TAG, "loaded art from $uri")
+ break
+ }
+ }
+ }
+ return null
+ }
+
+ /**
+ * Load a bitmap from a URI
+ * @param uri the uri to load
+ * @return bitmap, or null if couldn't be loaded
+ */
+ private fun loadBitmapFromUri(uri: Uri): Bitmap? {
+ // ImageDecoder requires a scheme of the following types
+ if (uri.scheme == null) {
+ return null
+ }
+
+ if (!uri.scheme.equals(ContentResolver.SCHEME_CONTENT) &&
+ !uri.scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE) &&
+ !uri.scheme.equals(ContentResolver.SCHEME_FILE)) {
+ return null
+ }
+
+ val source = ImageDecoder.createSource(context.getContentResolver(), uri)
+ return try {
+ ImageDecoder.decodeBitmap(source)
+ } catch (e: IOException) {
+ e.printStackTrace()
+ null
+ }
+ }
+
+ fun onMediaDataLoaded(key: String, data: MediaData) {
+ if (mediaEntries.containsKey(key)) {
+ // Otherwise this was removed already
+ mediaEntries.put(key, data)
+ listeners.forEach {
+ it.onMediaDataLoaded(key, data)
+ }
+ }
+ }
+
+ fun onNotificationRemoved(key: String) {
+ val removed = mediaEntries.remove(key)
+ if (removed != null) {
+ listeners.forEach {
+ it.onMediaDataRemoved(key)
+ }
+ }
+ }
+
+ private fun isMediaNotification(sbn: StatusBarNotification): Boolean {
+ if (!Utils.useQsMediaPlayer(context)) {
+ return false
+ }
+ if (!sbn.notification.hasMediaSession()) {
+ return false
+ }
+ val notificationStyle = sbn.notification.notificationStyle
+ if (Notification.DecoratedMediaCustomViewStyle::class.java.equals(notificationStyle) ||
+ Notification.MediaStyle::class.java.equals(notificationStyle)) {
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Are there any media notifications active?
+ */
+ fun hasActiveMedia() = mediaEntries.size > 0
+
+ fun hasAnyMedia(): Boolean {
+ // TODO: implement this when we implemented resumption
+ return hasActiveMedia()
+ }
+
+ interface Listener {
+
+ /**
+ * Called whenever there's new MediaData Loaded for the consumption in views
+ */
+ fun onMediaDataLoaded(key: String, data: MediaData) {}
+
+ /**
+ * Called whenever a previously existing Media notification was removed
+ */
+ fun onMediaDataRemoved(key: String) {}
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
new file mode 100644
index 0000000..6b1c520
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -0,0 +1,425 @@
+/*
+ * 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.media
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.annotation.IntDef
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewGroupOverlay
+import com.android.systemui.Interpolators
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.animation.UniqueObjectHostView
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * This manager is responsible for placement of the unique media view between the different hosts
+ * and animate the positions of the views to achieve seamless transitions.
+ */
+@Singleton
+class MediaHierarchyManager @Inject constructor(
+ private val context: Context,
+ private val statusBarStateController: SysuiStatusBarStateController,
+ private val keyguardStateController: KeyguardStateController,
+ private val bypassController: KeyguardBypassController,
+ private val mediaViewManager: MediaViewManager,
+ private val mediaMeasurementProvider: MediaMeasurementManager
+) {
+ /**
+ * The root overlay of the hierarchy. This is where the media notification is attached to
+ * whenever the view is transitioning from one host to another. It also make sure that the
+ * view is always in its final state when it is attached to a view host.
+ */
+ private var rootOverlay: ViewGroupOverlay? = null
+ private lateinit var currentState: MediaState
+ private val mediaCarousel
+ get() = mediaViewManager.mediaCarousel
+ private var animationStartState: MediaState? = null
+ private var statusbarState: Int = statusBarStateController.state
+ private var animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply {
+ interpolator = Interpolators.FAST_OUT_SLOW_IN
+ addUpdateListener {
+ updateTargetState()
+ applyState(animationStartState!!.interpolate(targetState!!, animatedFraction))
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ private var cancelled: Boolean = false
+
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true
+ }
+ override fun onAnimationEnd(animation: Animator?) {
+ if (!cancelled) {
+ applyTargetStateIfNotAnimating()
+ }
+ }
+
+ override fun onAnimationStart(animation: Animator?) {
+ cancelled = false
+ }
+ })
+ }
+ private var targetState: MediaState? = null
+ private val mediaHosts = arrayOfNulls<MediaHost>(LOCATION_LOCKSCREEN + 1)
+
+ /**
+ * The last location where this view was at before going to the desired location. This is
+ * useful for guided transitions.
+ */
+ @MediaLocation private var previousLocation = -1
+
+ /**
+ * The desired location where the view will be at the end of the transition.
+ */
+ @MediaLocation private var desiredLocation = -1
+
+ /**
+ * The current attachment location where the view is currently attached.
+ * Usually this matches the desired location except for animations whenever a view moves
+ * to the new desired location, during which it is in [IN_OVERLAY].
+ */
+ @MediaLocation private var currentAttachmentLocation = -1
+
+ var qsExpansion: Float = 0.0f
+ set(value) {
+ if (field != value) {
+ field = value
+ updateDesiredLocation()
+ if (getQSTransformationProgress() >= 0) {
+ updateTargetState()
+ applyTargetStateIfNotAnimating()
+ }
+ }
+ }
+
+ init {
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onStatePreChange(oldState: Int, newState: Int) {
+ // We're updating the location before the state change happens, since we want the
+ // location of the previous state to still be up to date when the animation starts
+ statusbarState = newState
+ updateDesiredLocation()
+ }
+
+ override fun onStateChanged(newState: Int) {
+ updateTargetState()
+ }
+ })
+ }
+
+ /**
+ * Register a media host and create a view can be attached to a view hierarchy
+ * and where the players will be placed in when the host is the currently desired state.
+ *
+ * @return the hostView associated with this location
+ */
+ fun register(mediaObject: MediaHost) : ViewGroup {
+ val viewHost = createUniqueObjectHost(mediaObject)
+ mediaObject.hostView = viewHost;
+ mediaHosts[mediaObject.location] = mediaObject
+ if (mediaObject.location == desiredLocation) {
+ // In case we are overriding a view that is already visible, make sure we attach it
+ // to this new host view in the below call
+ desiredLocation = -1
+ }
+ if (mediaObject.location == currentAttachmentLocation) {
+ currentAttachmentLocation = -1
+ }
+ updateDesiredLocation()
+ return viewHost
+ }
+
+ private fun createUniqueObjectHost(host: MediaHost): UniqueObjectHostView {
+ val viewHost = UniqueObjectHostView(context)
+ viewHost.measurementCache = mediaMeasurementProvider.obtainCache(host)
+ viewHost.onMeasureListener = { input ->
+ if (host.location == desiredLocation) {
+ // Measurement of the currently active player is happening, Let's make
+ // sure the player width is up to date
+ val measuringInput = host.getMeasuringInput(input)
+ mediaViewManager.setPlayerWidth(measuringInput.width)
+ }
+ }
+
+ viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(p0: View?) {
+ if (rootOverlay == null) {
+ rootOverlay = (viewHost.viewRootImpl.view.overlay as ViewGroupOverlay)
+ }
+ viewHost.removeOnAttachStateChangeListener(this)
+ }
+
+ override fun onViewDetachedFromWindow(p0: View?) {
+ }
+ })
+ return viewHost
+ }
+
+ /**
+ * Updates the location that the view should be in. If it changes, an animation may be triggered
+ * going from the old desired location to the new one.
+ */
+ private fun updateDesiredLocation() {
+ val desiredLocation = calculateLocation()
+ if (desiredLocation != this.desiredLocation) {
+ if (this.desiredLocation >= 0) {
+ previousLocation = this.desiredLocation
+ }
+ val isNewView = this.desiredLocation == -1
+ this.desiredLocation = desiredLocation
+ // Let's perform a transition
+ val animate = shouldAnimateTransition(desiredLocation, previousLocation)
+ val (animDuration, delay) = getAnimationParams(previousLocation, desiredLocation)
+ mediaViewManager.onDesiredLocationChanged(getHost(desiredLocation)?.currentState,
+ animate, animDuration, delay)
+ performTransitionToNewLocation(isNewView, animate)
+ }
+ }
+
+ private fun performTransitionToNewLocation(isNewView: Boolean, animate: Boolean) {
+ if (previousLocation < 0 || isNewView) {
+ cancelAnimationAndApplyDesiredState()
+ return
+ }
+ val currentHost = getHost(desiredLocation)
+ val previousHost = getHost(previousLocation)
+ if (currentHost == null || previousHost == null) {
+ cancelAnimationAndApplyDesiredState()
+ return
+ }
+ updateTargetState()
+ if (isCurrentlyInGuidedTransformation()) {
+ applyTargetStateIfNotAnimating()
+ } else if (animate) {
+ animator.cancel()
+ if (currentAttachmentLocation == IN_OVERLAY
+ || !previousHost.hostView.isAttachedToWindow) {
+ // Let's animate to the new position, starting from the current position
+ // We also go in here in case the view was detached, since the bounds wouldn't
+ // be correct anymore
+ animationStartState = currentState.copy()
+ } else {
+ // otherwise, let's take the freshest state, since the current one could
+ // be outdated
+ animationStartState = previousHost.currentState.copy()
+ }
+ adjustAnimatorForTransition(desiredLocation, previousLocation)
+ animator.start()
+ } else {
+ cancelAnimationAndApplyDesiredState()
+ }
+ }
+
+ private fun shouldAnimateTransition(
+ @MediaLocation currentLocation: Int,
+ @MediaLocation previousLocation: Int
+ ): Boolean {
+ if (currentLocation == LOCATION_QQS
+ && previousLocation == LOCATION_LOCKSCREEN
+ && (statusBarStateController.leaveOpenOnKeyguardHide()
+ || statusbarState == StatusBarState.SHADE_LOCKED)) {
+ // Usually listening to the isShown is enough to determine this, but there is some
+ // non-trivial reattaching logic happening that will make the view not-shown earlier
+ return true
+ }
+ return mediaCarousel.isShown || animator.isRunning
+ }
+
+ private fun adjustAnimatorForTransition(desiredLocation: Int, previousLocation: Int) {
+ val (animDuration, delay) = getAnimationParams(previousLocation, desiredLocation)
+ animator.apply {
+ duration = animDuration
+ startDelay = delay
+ }
+
+ }
+
+ private fun getAnimationParams(previousLocation: Int, desiredLocation: Int): Pair<Long, Long> {
+ var animDuration = 200L
+ var delay = 0L
+ if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) {
+ // Going to the full shade, let's adjust the animation duration
+ if (statusbarState == StatusBarState.SHADE
+ && keyguardStateController.isKeyguardFadingAway) {
+ delay = keyguardStateController.keyguardFadingAwayDelay
+ }
+ animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong()
+ } else if (previousLocation == LOCATION_QQS && desiredLocation == LOCATION_LOCKSCREEN) {
+ animDuration = StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR.toLong()
+ }
+ return animDuration to delay
+ }
+
+ private fun applyTargetStateIfNotAnimating() {
+ if (!animator.isRunning) {
+ // Let's immediately apply the target state (which is interpolated) if there is
+ // no animation running. Otherwise the animation update will already update
+ // the location
+ applyState(targetState!!)
+ }
+ }
+
+ /**
+ * Updates the state that the view wants to be in at the end of the animation.
+ */
+ private fun updateTargetState() {
+ if (isCurrentlyInGuidedTransformation()) {
+ val progress = getTransformationProgress()
+ val currentHost = getHost(desiredLocation)!!
+ val previousHost = getHost(previousLocation)!!
+ val newState = currentHost.currentState
+ val previousState = previousHost.currentState
+ targetState = previousState.interpolate(newState, progress)
+ } else {
+ targetState = getHost(desiredLocation)?.currentState
+ }
+ }
+
+ /**
+ * @return true if this transformation is guided by an external progress like a finger
+ */
+ private fun isCurrentlyInGuidedTransformation() : Boolean {
+ return getTransformationProgress() >= 0
+ }
+
+ /**
+ * @return the current transformation progress if we're in a guided transformation and -1
+ * otherwise
+ */
+ private fun getTransformationProgress(): Float {
+ val progress = getQSTransformationProgress()
+ if (progress >= 0) {
+ return progress
+ }
+ return -1.0f
+ }
+
+ private fun getQSTransformationProgress(): Float {
+ val currentHost = getHost(desiredLocation)
+ val previousHost = getHost(previousLocation)
+ if (currentHost?.location == LOCATION_QS) {
+ if (previousHost?.location == LOCATION_QQS) {
+ return qsExpansion
+ }
+ }
+ return -1.0f
+ }
+
+ private fun getHost(@MediaLocation location: Int): MediaHost? {
+ if (location < 0) {
+ return null
+ }
+ return mediaHosts[location]
+ }
+
+ private fun cancelAnimationAndApplyDesiredState() {
+ animator.cancel()
+ getHost(desiredLocation)?.let {
+ applyState(it.currentState)
+ }
+ }
+
+ private fun applyState(state: MediaState) {
+ currentState = state.copy()
+ mediaViewManager.setCurrentState(currentState)
+ updateHostAttachment()
+ if (currentAttachmentLocation == IN_OVERLAY) {
+ val boundsOnScreen = state.boundsOnScreen
+ mediaCarousel.setLeftTopRightBottom(
+ boundsOnScreen.left,
+ boundsOnScreen.top,
+ boundsOnScreen.right,
+ boundsOnScreen.bottom)
+ }
+ }
+
+ private fun updateHostAttachment() {
+ val inOverlay = isTransitionRunning() && rootOverlay != null
+ val newLocation = if (inOverlay) IN_OVERLAY else desiredLocation
+ if (currentAttachmentLocation != newLocation) {
+ currentAttachmentLocation = newLocation
+
+ // Remove the carousel from the old host
+ (mediaCarousel.parent as ViewGroup?)?.removeView(mediaCarousel)
+
+ // Add it to the new one
+ val targetHost = getHost(desiredLocation)!!.hostView
+ if (inOverlay) {
+ rootOverlay!!.add(mediaCarousel)
+ } else {
+ targetHost.addView(mediaCarousel)
+ mediaViewManager.onViewReattached()
+ }
+ }
+ }
+
+ private fun isTransitionRunning(): Boolean {
+ return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f
+ || animator.isRunning
+ }
+
+ @MediaLocation
+ private fun calculateLocation() : Int {
+ val onLockscreen = (!bypassController.bypassEnabled
+ && (statusbarState == StatusBarState.KEYGUARD
+ || statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+ return when {
+ qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS
+ qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
+ onLockscreen -> LOCATION_LOCKSCREEN
+ else -> LOCATION_QQS
+ }
+ }
+
+ /**
+ * The expansion of quick settings
+ */
+ @IntDef(prefix = ["LOCATION_"], value = [LOCATION_QS, LOCATION_QQS, LOCATION_LOCKSCREEN])
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class MediaLocation
+
+ companion object {
+ /**
+ * Attached in expanded quick settings
+ */
+ const val LOCATION_QS = 0
+
+ /**
+ * Attached in the collapsed QS
+ */
+ const val LOCATION_QQS = 1
+
+ /**
+ * Attached on the lock screen
+ */
+ const val LOCATION_LOCKSCREEN = 2
+
+ /**
+ * Attached at the root of the hierarchy in an overlay
+ */
+ const val IN_OVERLAY = -1000
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
new file mode 100644
index 0000000..6e7b6bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -0,0 +1,159 @@
+package com.android.systemui.media
+
+import android.graphics.Rect
+import android.util.MathUtils
+import android.view.View
+import android.view.View.OnAttachStateChangeListener
+import android.view.ViewGroup
+import com.android.systemui.media.MediaHierarchyManager.MediaLocation
+import com.android.systemui.util.animation.MeasurementInput
+import javax.inject.Inject
+
+class MediaHost @Inject constructor(
+ private val state: MediaHostState,
+ private val mediaHierarchyManager: MediaHierarchyManager,
+ private val mediaDataManager: MediaDataManager
+) : MediaState by state {
+ lateinit var hostView: ViewGroup
+ var location: Int = -1
+ private set
+ var visibleChangedListener: ((Boolean) -> Unit)? = null
+ var visible: Boolean = false
+ private set
+
+ private val tmpLocationOnScreen: IntArray = intArrayOf(0, 0)
+
+ /**
+ * Get the current Media state. This also updates the location on screen
+ */
+ val currentState : MediaState
+ get () {
+ hostView.getLocationOnScreen(tmpLocationOnScreen)
+ var left = tmpLocationOnScreen[0] + hostView.paddingLeft
+ var top = tmpLocationOnScreen[1] + hostView.paddingTop
+ var right = tmpLocationOnScreen[0] + hostView.width - hostView.paddingRight
+ var bottom = tmpLocationOnScreen[1] + hostView.height - hostView.paddingBottom
+ // Handle cases when the width or height is 0 but it has padding. In those cases
+ // the above could return negative widths, which is wrong
+ if (right < left) {
+ left = 0
+ right = 0;
+ }
+ if (bottom < top) {
+ bottom = 0
+ top = 0;
+ }
+ state.boundsOnScreen.set(left, top, right, bottom)
+ return state
+ }
+
+ private val listener = object : MediaDataManager.Listener {
+ override fun onMediaDataLoaded(key: String, data: MediaData) {
+ updateViewVisibility()
+ }
+
+ override fun onMediaDataRemoved(key: String) {
+ updateViewVisibility()
+ }
+ }
+
+ /**
+ * Initialize this MediaObject and create a host view.
+ *
+ * @param location the location this host name has. Used to identify the host during
+ * transitions.
+ */
+ fun init(@MediaLocation location: Int) {
+ this.location = location;
+ hostView = mediaHierarchyManager.register(this)
+ hostView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View?) {
+ mediaDataManager.addListener(listener)
+ updateViewVisibility()
+ }
+
+ override fun onViewDetachedFromWindow(v: View?) {
+ mediaDataManager.removeListener(listener)
+ }
+ })
+ updateViewVisibility()
+ }
+
+ private fun updateViewVisibility() {
+ if (showsOnlyActiveMedia) {
+ visible = mediaDataManager.hasActiveMedia()
+ } else {
+ visible = mediaDataManager.hasAnyMedia()
+ }
+ hostView.visibility = if (visible) View.VISIBLE else View.GONE
+ visibleChangedListener?.invoke(visible)
+ }
+
+ class MediaHostState @Inject constructor() : MediaState {
+ var measurementInput: MediaMeasurementInput? = null
+ override var expansion: Float = 0.0f
+ override var showsOnlyActiveMedia: Boolean = false
+ override val boundsOnScreen: Rect = Rect()
+
+ override fun copy() : MediaState {
+ val mediaHostState = MediaHostState()
+ mediaHostState.expansion = expansion
+ mediaHostState.showsOnlyActiveMedia = showsOnlyActiveMedia
+ mediaHostState.boundsOnScreen.set(boundsOnScreen)
+ mediaHostState.measurementInput = measurementInput
+ return mediaHostState
+ }
+
+ override fun interpolate(other: MediaState, amount: Float) : MediaState {
+ val result = MediaHostState()
+ result.expansion = MathUtils.lerp(expansion, other.expansion, amount)
+ val left = MathUtils.lerp(boundsOnScreen.left.toFloat(),
+ other.boundsOnScreen.left.toFloat(), amount).toInt()
+ val top = MathUtils.lerp(boundsOnScreen.top.toFloat(),
+ other.boundsOnScreen.top.toFloat(), amount).toInt()
+ val right = MathUtils.lerp(boundsOnScreen.right.toFloat(),
+ other.boundsOnScreen.right.toFloat(), amount).toInt()
+ val bottom = MathUtils.lerp(boundsOnScreen.bottom.toFloat(),
+ other.boundsOnScreen.bottom.toFloat(), amount).toInt()
+ result.boundsOnScreen.set(left, top, right, bottom)
+ result.showsOnlyActiveMedia = other.showsOnlyActiveMedia || showsOnlyActiveMedia
+ if (amount > 0.0f) {
+ if (other is MediaHostState) {
+ result.measurementInput = other.measurementInput
+ }
+ } else {
+ result.measurementInput
+ }
+ return result
+ }
+
+ override fun getMeasuringInput(input: MeasurementInput): MediaMeasurementInput {
+ measurementInput = MediaMeasurementInput(input, expansion)
+ return measurementInput as MediaMeasurementInput
+ }
+ }
+}
+
+interface MediaState {
+ var expansion: Float
+ var showsOnlyActiveMedia: Boolean
+ val boundsOnScreen: Rect
+ fun copy() : MediaState
+ fun interpolate(other: MediaState, amount: Float) : MediaState
+ fun getMeasuringInput(input: MeasurementInput): MediaMeasurementInput
+}
+/**
+ * The measurement input for a Media View
+ */
+data class MediaMeasurementInput(
+ private val viewInput: MeasurementInput,
+ val expansion: Float) : MeasurementInput by viewInput {
+
+ override fun sameAs(input: MeasurementInput?): Boolean {
+ if (!(input is MediaMeasurementInput)) {
+ return false
+ }
+ return width == input.width && expansion == input.expansion
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaMeasurementManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaMeasurementManager.kt
new file mode 100644
index 0000000..4bbf5eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaMeasurementManager.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.media
+
+import com.android.systemui.util.animation.BaseMeasurementCache
+import com.android.systemui.util.animation.GuaranteedMeasurementCache
+import com.android.systemui.util.animation.MeasurementCache
+import com.android.systemui.util.animation.MeasurementInput
+import com.android.systemui.util.animation.MeasurementOutput
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * A class responsible creating measurement caches for media hosts which also coordinates with
+ * the view manager to obtain sizes for unknown measurement inputs.
+ */
+@Singleton
+class MediaMeasurementManager @Inject constructor(
+ private val mediaViewManager: MediaViewManager
+) {
+ private val baseCache: MeasurementCache
+
+ init {
+ baseCache = BaseMeasurementCache()
+ }
+
+ private fun provideMeasurement(input: MediaMeasurementInput) : MeasurementOutput? {
+ return mediaViewManager.obtainMeasurement(input)
+ }
+
+ /**
+ * Obtain a guaranteed measurement cache for a host view. The measurement cache makes sure that
+ * requesting any size from the cache will always return the correct value.
+ */
+ fun obtainCache(host: MediaState): GuaranteedMeasurementCache {
+ val remapper = { input: MeasurementInput ->
+ host.getMeasuringInput(input)
+ }
+ val provider = { input: MeasurementInput ->
+ provideMeasurement(input as MediaMeasurementInput)
+ }
+ return GuaranteedMeasurementCache(baseCache, remapper, provider)
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
new file mode 100644
index 0000000..8db9dcc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
@@ -0,0 +1,324 @@
+package com.android.systemui.media
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.HorizontalScrollView
+import android.widget.LinearLayout
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.media.InfoMediaManager
+import com.android.settingslib.media.LocalMediaManager
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.notification.VisualStabilityManager
+import com.android.systemui.util.animation.MeasurementOutput
+import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.concurrency.DelayableExecutor
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Class that is responsible for keeping the view carousel up to date.
+ * This also handles changes in state and applies them to the media carousel like the expansion.
+ */
+@Singleton
+class MediaViewManager @Inject constructor(
+ private val context: Context,
+ @Main private val foregroundExecutor: Executor,
+ @Background private val backgroundExecutor: DelayableExecutor,
+ private val localBluetoothManager: LocalBluetoothManager?,
+ private val visualStabilityManager: VisualStabilityManager,
+ private val activityStarter: ActivityStarter,
+ mediaManager: MediaDataManager
+) {
+ private var playerWidth: Int = 0
+ private var playerWidthPlusPadding: Int = 0
+ private var desiredState: MediaHost.MediaHostState? = null
+ private var currentState: MediaState? = null
+ val mediaCarousel: HorizontalScrollView
+ private val mediaContent: ViewGroup
+ private val mediaPlayers: MutableMap<String, MediaControlPanel> = mutableMapOf()
+ private val visualStabilityCallback : VisualStabilityManager.Callback
+ private var activeMediaIndex: Int = 0
+ private var needsReordering: Boolean = false
+ private var scrollIntoCurrentMedia: Int = 0
+ private var currentlyExpanded = true
+ set(value) {
+ if (field != value) {
+ field = value
+ for (player in mediaPlayers.values) {
+ player.setListening(field)
+ }
+ }
+ }
+ private val scrollChangedListener = object : View.OnScrollChangeListener {
+ override fun onScrollChange(
+ v: View?,
+ scrollX: Int,
+ scrollY: Int,
+ oldScrollX: Int,
+ oldScrollY: Int
+ ) {
+ if (playerWidthPlusPadding == 0) {
+ return
+ }
+ onMediaScrollingChanged(scrollX / playerWidthPlusPadding,
+ scrollX % playerWidthPlusPadding)
+ }
+ }
+
+ init {
+ mediaCarousel = inflateMediaCarousel()
+ mediaCarousel.setOnScrollChangeListener(scrollChangedListener)
+ mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
+ visualStabilityCallback = VisualStabilityManager.Callback {
+ if (needsReordering) {
+ needsReordering = false
+ reorderAllPlayers()
+ }
+ // Let's reset our scroll position
+ mediaCarousel.scrollX = 0
+ }
+ visualStabilityManager.addReorderingAllowedCallback(visualStabilityCallback,
+ true /* persistent */)
+ mediaManager.addListener(object : MediaDataManager.Listener {
+ override fun onMediaDataLoaded(key: String, data: MediaData) {
+ updateView(key, data)
+ updatePlayerVisibilities()
+ }
+
+ override fun onMediaDataRemoved(key: String) {
+ val removed = mediaPlayers.remove(key)
+ removed?.apply {
+ val beforeActive = mediaContent.indexOfChild(removed.view?.player) <=
+ activeMediaIndex
+ mediaContent.removeView(removed.view?.player)
+ removed.onDestroy()
+ updateMediaPaddings()
+ if (beforeActive) {
+ // also update the index here since the scroll below might not always lead
+ // to a scrolling changed
+ activeMediaIndex = Math.max(0, activeMediaIndex - 1)
+ mediaCarousel.scrollX = Math.max(mediaCarousel.scrollX -
+ playerWidthPlusPadding, 0)
+ }
+ updatePlayerVisibilities()
+ }
+ }
+ })
+ }
+
+ private fun inflateMediaCarousel(): HorizontalScrollView {
+ return LayoutInflater.from(context).inflate(R.layout.media_carousel,
+ UniqueObjectHostView(context), false) as HorizontalScrollView
+ }
+
+ private fun reorderAllPlayers() {
+ for (mediaPlayer in mediaPlayers.values) {
+ val view = mediaPlayer.view?.player
+ if (mediaPlayer.isPlaying && mediaContent.indexOfChild(view) != 0) {
+ mediaContent.removeView(view)
+ mediaContent.addView(view, 0)
+ }
+ }
+ updateMediaPaddings()
+ updatePlayerVisibilities()
+ }
+
+ private fun onMediaScrollingChanged(newIndex: Int, scrollInAmount: Int) {
+ val wasScrolledIn = scrollIntoCurrentMedia != 0
+ scrollIntoCurrentMedia = scrollInAmount
+ val nowScrolledIn = scrollIntoCurrentMedia != 0
+ if (newIndex != activeMediaIndex || wasScrolledIn != nowScrolledIn) {
+ activeMediaIndex = newIndex
+ updatePlayerVisibilities()
+ }
+ }
+
+ private fun updatePlayerVisibilities() {
+ val scrolledIn = scrollIntoCurrentMedia != 0
+ for (i in 0 until mediaContent.childCount) {
+ val view = mediaContent.getChildAt(i)
+ val visible = (i == activeMediaIndex) || ((i == (activeMediaIndex + 1)) && scrolledIn)
+ view.visibility = if (visible) View.VISIBLE else View.INVISIBLE
+ }
+ }
+
+ private fun updateView(key: String, data: MediaData) {
+ var existingPlayer = mediaPlayers[key]
+ if (existingPlayer == null) {
+ // Set up listener for device changes
+ // TODO: integrate with MediaTransferManager?
+ val imm = InfoMediaManager(context, data.packageName,
+ null /* notification */, localBluetoothManager)
+ val routeManager = LocalMediaManager(context, localBluetoothManager,
+ imm, data.packageName)
+
+ existingPlayer = MediaControlPanel(context, routeManager, foregroundExecutor,
+ backgroundExecutor, activityStarter)
+ existingPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context),
+ mediaContent))
+ mediaPlayers[key] = existingPlayer
+ val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT)
+ existingPlayer.view?.player?.setLayoutParams(lp)
+ existingPlayer.setListening(currentlyExpanded)
+ if (existingPlayer.isPlaying) {
+ mediaContent.addView(existingPlayer.view?.player, 0)
+ } else {
+ mediaContent.addView(existingPlayer.view?.player)
+ }
+ updatePlayerToCurrentState(existingPlayer)
+ } else if (existingPlayer.isPlaying &&
+ mediaContent.indexOfChild(existingPlayer.view?.player) != 0) {
+ if (visualStabilityManager.isReorderingAllowed) {
+ mediaContent.removeView(existingPlayer.view?.player)
+ mediaContent.addView(existingPlayer.view?.player, 0)
+ } else {
+ needsReordering = true
+ }
+ }
+ existingPlayer.bind(data)
+ // Resetting the progress to make sure it's taken into account for the latest
+ // motion model
+ existingPlayer.view?.player?.progress = currentState?.expansion ?: 0.0f
+ updateMediaPaddings()
+ }
+
+ private fun updatePlayerToCurrentState(existingPlayer: MediaControlPanel) {
+ if (desiredState != null && desiredState!!.measurementInput != null) {
+ // make sure the player width is set to the current state
+ existingPlayer.setPlayerWidth(playerWidth)
+ }
+ }
+
+ private fun updateMediaPaddings() {
+ val padding = context.resources.getDimensionPixelSize(R.dimen.qs_media_padding)
+ val childCount = mediaContent.childCount
+ for (i in 0 until childCount) {
+ val mediaView = mediaContent.getChildAt(i)
+ val desiredPaddingEnd = if (i == childCount - 1) 0 else padding
+ val layoutParams = mediaView.layoutParams as ViewGroup.MarginLayoutParams
+ if (layoutParams.marginEnd != desiredPaddingEnd) {
+ layoutParams.marginEnd = desiredPaddingEnd
+ mediaView.layoutParams = layoutParams
+ }
+ }
+ }
+
+ /**
+ * Set the current state of a view. This is updated often during animations and we shouldn't
+ * do anything expensive.
+ */
+ fun setCurrentState(state: MediaState) {
+ currentState = state
+ currentlyExpanded = state.expansion > 0
+ for (mediaPlayer in mediaPlayers.values) {
+ val view = mediaPlayer.view?.player
+ view?.progress = state.expansion
+ }
+ }
+
+ /**
+ * The desired location of this view has changed. We should remeasure the view to match
+ * the new bounds and kick off bounds animations if necessary.
+ * If an animation is happening, an animation is kicked of externally, which sets a new
+ * current state until we reach the targetState.
+ *
+ * @param desiredState the target state we're transitioning to
+ * @param animate should this be animated
+ */
+ fun onDesiredLocationChanged(
+ desiredState: MediaState?,
+ animate: Boolean,
+ duration: Long,
+ startDelay: Long
+ ) {
+ if (desiredState is MediaHost.MediaHostState) {
+ // This is a hosting view, let's remeasure our players
+ this.desiredState = desiredState
+ val width = desiredState.boundsOnScreen.width()
+ if (playerWidth != width) {
+ setPlayerWidth(width)
+ for (mediaPlayer in mediaPlayers.values) {
+ if (animate && mediaPlayer.view?.player?.visibility == View.VISIBLE) {
+ mediaPlayer.animatePendingSizeChange(duration, startDelay)
+ }
+ }
+ val widthSpec = desiredState.measurementInput?.widthMeasureSpec ?: 0
+ val heightSpec = desiredState.measurementInput?.heightMeasureSpec ?: 0
+ var left = 0
+ for (i in 0 until mediaContent.childCount) {
+ val view = mediaContent.getChildAt(i)
+ view.measure(widthSpec, heightSpec)
+ view.layout(left, 0, left + width, view.measuredHeight)
+ left = left + playerWidthPlusPadding
+ }
+ }
+ }
+ }
+
+ fun setPlayerWidth(width: Int) {
+ if (width != playerWidth) {
+ playerWidth = width
+ playerWidthPlusPadding = playerWidth + context.resources.getDimensionPixelSize(
+ R.dimen.qs_media_padding)
+ for (mediaPlayer in mediaPlayers.values) {
+ mediaPlayer.setPlayerWidth(width)
+ }
+ // The player width has changed, let's update the scroll position to make sure
+ // it's still at the same place
+ var newScroll = activeMediaIndex * playerWidthPlusPadding
+ if (scrollIntoCurrentMedia > playerWidthPlusPadding) {
+ newScroll += playerWidthPlusPadding
+ - (scrollIntoCurrentMedia - playerWidthPlusPadding)
+ } else {
+ newScroll += scrollIntoCurrentMedia
+ }
+ mediaCarousel.scrollX = newScroll
+ }
+ }
+
+ /**
+ * Get a measurement for the given input state. This measures the first player and returns
+ * its bounds as if it were measured with the given measurement dimensions
+ */
+ fun obtainMeasurement(input: MediaMeasurementInput): MeasurementOutput? {
+ val firstPlayer = mediaPlayers.values.firstOrNull() ?: return null
+ var result: MeasurementOutput? = null
+ firstPlayer.view?.player?.let {
+ // Let's measure the size of the first player and return its height
+ val previousProgress = it.progress
+ val previousRight = it.right
+ val previousBottom = it.bottom
+ it.progress = input.expansion
+ firstPlayer.measure(input)
+ // Relayouting is necessary in motionlayout to obtain its size properly ....
+ it.layout(0, 0, it.measuredWidth, it.measuredHeight)
+ result = MeasurementOutput(it.measuredWidth, it.measuredHeight)
+ it.progress = previousProgress
+ if (desiredState != null) {
+ // remeasure it to the old size again!
+ firstPlayer.measure(desiredState!!.measurementInput)
+ it.layout(0, 0, previousRight, previousBottom)
+ }
+ }
+ return result
+ }
+
+ fun onViewReattached() {
+ if (desiredState is MediaHost.MediaHostState) {
+ // HACK: MotionLayout doesn't always properly reevalate the state, let's kick of
+ // a measure to force it.
+ val widthSpec = desiredState!!.measurementInput?.widthMeasureSpec ?: 0
+ val heightSpec = desiredState!!.measurementInput?.heightMeasureSpec ?: 0
+ for (mediaPlayer in mediaPlayers.values) {
+ mediaPlayer.view?.player?.measure(widthSpec, heightSpec)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
new file mode 100644
index 0000000..764dbe6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.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.systemui.media
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.TextView
+
+import androidx.constraintlayout.motion.widget.MotionLayout
+
+import com.android.systemui.R
+
+/**
+ * ViewHolder for a media player.
+ */
+class PlayerViewHolder private constructor(itemView: View) {
+
+ val player = itemView as MotionLayout
+ val background = itemView.requireViewById<View>(R.id.media_background)
+
+ // Player information
+ val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
+ val appName = itemView.requireViewById<TextView>(R.id.app_name)
+ val albumView = itemView.requireViewById<ImageView>(R.id.album_art)
+ val titleText = itemView.requireViewById<TextView>(R.id.header_title)
+ val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
+
+ // Output switcher
+ val seamless = itemView.findViewById<ViewGroup>(R.id.media_seamless)
+ val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
+ val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
+
+ // Seek bar
+ val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
+ val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
+ val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
+
+ // Action Buttons
+ val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
+ val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
+ val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
+ val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
+ val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
+
+ init {
+ (background.background as IlluminationDrawable).let {
+ it.setupTouch(seamless, player)
+ it.setupTouch(action0, player)
+ it.setupTouch(action1, player)
+ it.setupTouch(action2, player)
+ it.setupTouch(action3, player)
+ it.setupTouch(action4, player)
+ }
+ }
+
+ fun getAction(id: Int): ImageButton {
+ return when (id) {
+ R.id.action0 -> action0
+ R.id.action1 -> action1
+ R.id.action2 -> action2
+ R.id.action3 -> action3
+ R.id.action4 -> action4
+ else -> {
+ throw IllegalArgumentException()
+ }
+ }
+ }
+
+ // Settings screen
+ val options = itemView.requireViewById<View>(R.id.qs_media_controls_options)
+
+ companion object {
+ /**
+ * Creates a PlayerViewHolder.
+ *
+ * @param inflater LayoutInflater to use to inflate the layout.
+ * @param parent Parent of inflated view.
+ */
+ @JvmStatic fun create(inflater: LayoutInflater, parent: ViewGroup): PlayerViewHolder {
+ val v = inflater.inflate(R.layout.qs_media_panel, parent, false)
+ return PlayerViewHolder(v)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 51c157a..110b08c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.content.res.ColorStateList
+import android.graphics.Color
import android.text.format.DateUtils
import android.view.View
import android.widget.SeekBar
@@ -46,18 +47,6 @@
/** Updates seek bar views when the data model changes. */
@UiThread
override fun onChanged(data: SeekBarViewModel.Progress) {
-
- data.color?.let {
- var tintList = ColorStateList.valueOf(it)
- seekBarView.setThumbTintList(tintList)
- tintList = tintList.withAlpha(192) // 75%
- seekBarView.setProgressTintList(tintList)
- tintList = tintList.withAlpha(128) // 50%
- seekBarView.setProgressBackgroundTintList(tintList)
- elapsedTimeView.setTextColor(it)
- totalTimeView.setTextColor(it)
- }
-
if (!data.enabled) {
seekBarView.setEnabled(false)
seekBarView.getThumb().setAlpha(0)
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index f72a74b..b08124b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -67,7 +67,7 @@
/** ViewModel for seek bar in QS media player. */
class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
- private var _data = Progress(false, false, null, null, null)
+ private var _data = Progress(false, false, null, null)
set(value) {
field = value
_progress.postValue(value)
@@ -100,10 +100,9 @@
/**
* Updates media information.
* @param mediaController controller for media session
- * @param color foreground color for UI elements
*/
@WorkerThread
- fun updateController(mediaController: MediaController?, color: Int) {
+ fun updateController(mediaController: MediaController?) {
controller = mediaController
playbackState = controller?.playbackState
val mediaMetadata = controller?.metadata
@@ -113,7 +112,7 @@
val enabled = if (playbackState == null ||
playbackState?.getState() == PlaybackState.STATE_NONE ||
(duration != null && duration <= 0)) false else true
- _data = Progress(enabled, seekAvailable, position, duration, color)
+ _data = Progress(enabled, seekAvailable, position, duration)
if (shouldPollPlaybackPosition()) {
checkPlaybackPosition()
}
@@ -191,7 +190,6 @@
val enabled: Boolean,
val seekAvailable: Boolean,
val elapsedTime: Int?,
- val duration: Int?,
- val color: Int?
+ val duration: Int?
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/UnboundHorizontalScrollView.kt b/packages/SystemUI/src/com/android/systemui/media/UnboundHorizontalScrollView.kt
new file mode 100644
index 0000000..8efc954
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/UnboundHorizontalScrollView.kt
@@ -0,0 +1,31 @@
+package com.android.systemui.media
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.HorizontalScrollView
+
+/**
+ * A Horizontal scrollview that doesn't limit itself to the childs bounds. This is useful
+ * when only measuring children but not the parent, when trying to apply a new scroll position
+ */
+class UnboundHorizontalScrollView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
+ : HorizontalScrollView(context, attrs, defStyleAttr) {
+
+ /**
+ * Allow all scrolls to go through, use base implementation
+ */
+ override fun scrollTo(x: Int, y: Int) {
+ if (mScrollX != x || mScrollY != y) {
+ val oldX: Int = mScrollX
+ val oldY: Int = mScrollY
+ mScrollX = x
+ mScrollY = y
+ invalidateParentCaches()
+ onScrollChanged(mScrollX, mScrollY, oldX, oldY)
+ if (!awakenScrollBars()) {
+ postInvalidateOnAnimation()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
index f900f1e..ccf58ba 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
@@ -39,7 +39,7 @@
public class SysUiState implements Dumpable {
private static final String TAG = SysUiState.class.getSimpleName();
- public static final boolean DEBUG = true;
+ public static final boolean DEBUG = false;
private @QuickStepContract.SystemUiStateFlags int mFlags;
private final List<SysUiStateCallback> mCallbacks = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index f322489..13516a9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -65,6 +65,10 @@
@Retention(RetentionPolicy.SOURCE)
public @interface TransitionDirection {}
+ public static boolean isInPipDirection(@TransitionDirection int direction) {
+ return direction == TRANSITION_DIRECTION_TO_PIP;
+ }
+
public static boolean isOutPipDirection(@TransitionDirection int direction) {
return direction == TRANSITION_DIRECTION_TO_FULLSCREEN
|| direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
@@ -104,6 +108,12 @@
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
+ } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
+ && mCurrentAnimator.isRunning()) {
+ // If we are still animating the fade into pip, then just move the surface and ensure
+ // we update with the new destination bounds, but don't interrupt the existing animation
+ // with a new bounds
+ mCurrentAnimator.setDestinationBounds(endBounds);
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
&& mCurrentAnimator.isRunning()) {
mCurrentAnimator.setDestinationBounds(endBounds);
@@ -265,8 +275,7 @@
boolean inScaleTransition() {
if (mAnimationType != ANIM_TYPE_BOUNDS) return false;
- final int direction = getTransitionDirection();
- return !isOutPipDirection(direction) && direction != TRANSITION_DIRECTION_TO_PIP;
+ return !isInPipDirection(getTransitionDirection());
}
/**
@@ -354,7 +363,11 @@
getCastedFractionValue(start.bottom, end.bottom, fraction));
setCurrentValue(mTmpRect);
if (inScaleTransition()) {
- getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
+ if (isOutPipDirection(getTransitionDirection())) {
+ getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect);
+ } else {
+ getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
+ }
} else {
getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
}
@@ -376,7 +389,8 @@
// NOTE: intentionally does not apply the transaction here.
// this end transaction should get executed synchronously with the final
// WindowContainerTransaction in task organizer
- getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds());
+ getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds())
+ .crop(tx, leash, getDestinationBounds());
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 3eeadc3..93605170 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -61,12 +61,6 @@
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final Rect mTmpInsets = new Rect();
- /**
- * Tracks the destination bounds, used for any following
- * {@link #onMovementBoundsChanged(Rect, Rect, Rect, DisplayInfo)} calculations.
- */
- private final Rect mLastDestinationBounds = new Rect();
-
private ComponentName mLastPipComponentName;
private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
private Size mReentrySize;
@@ -198,17 +192,16 @@
mReentrySnapFraction = INVALID_SNAP_FRACTION;
mReentrySize = null;
mLastPipComponentName = null;
- mLastDestinationBounds.setEmpty();
- }
-
- public Rect getLastDestinationBounds() {
- return mLastDestinationBounds;
}
public Rect getDisplayBounds() {
return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
}
+ public int getDisplayRotation() {
+ return mDisplayInfo.rotation;
+ }
+
/**
* Responds to IPinnedStackListener on {@link DisplayInfo} change.
* It will normally follow up with a
@@ -258,7 +251,6 @@
false /* useCurrentMinEdgeSize */);
}
mAspectRatio = aspectRatio;
- mLastDestinationBounds.set(destinationBounds);
return destinationBounds;
}
@@ -272,8 +264,8 @@
*
* @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
*/
- public boolean onDisplayRotationChanged(Rect outBounds, int displayId, int fromRotation,
- int toRotation, WindowContainerTransaction t) {
+ public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, int displayId,
+ int fromRotation, int toRotation, WindowContainerTransaction t) {
// Bail early if the event is not sent to current {@link #mDisplayInfo}
if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
return false;
@@ -291,7 +283,7 @@
}
// Calculate the snap fraction of the current stack along the old movement bounds
- final Rect postChangeStackBounds = new Rect(mLastDestinationBounds);
+ final Rect postChangeStackBounds = new Rect(oldBounds);
final float snapFraction = getSnapFraction(postChangeStackBounds);
// Populate the new {@link #mDisplayInfo}.
@@ -309,7 +301,6 @@
snapFraction);
outBounds.set(postChangeStackBounds);
- mLastDestinationBounds.set(outBounds);
t.setBounds(pinnedStackInfo.stackToken, outBounds);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 8d6ce47..ae61006 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -16,6 +16,9 @@
package com.android.systemui.pip;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
@@ -25,25 +28,30 @@
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
+import static com.android.systemui.pip.PipAnimationController.isInPipDirection;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.util.Log;
import android.util.Size;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import com.android.internal.os.SomeArgs;
@@ -51,6 +59,7 @@
import com.android.systemui.pip.phone.PipUpdateThread;
import com.android.systemui.stackdivider.Divider;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -90,7 +99,7 @@
private final Rect mLastReportedBounds = new Rect();
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
+ private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
private final Divider mSplitDivider;
// These callbacks are called on the update thread
@@ -110,7 +119,8 @@
@Override
public void onPipAnimationEnd(SurfaceControl.Transaction tx,
PipAnimationController.PipTransitionAnimator animator) {
- finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection());
+ finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection(),
+ animator.getAnimationType());
mMainHandler.post(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -170,7 +180,7 @@
case MSG_FINISH_RESIZE: {
SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
Rect toBounds = (Rect) args.arg3;
- finishResize(tx, toBounds, args.argi1 /* direction */);
+ finishResize(tx, toBounds, args.argi1 /* direction */, -1);
if (updateBoundsCallback != null) {
updateBoundsCallback.accept(toBounds);
}
@@ -240,28 +250,76 @@
}
/**
- * Dismiss PiP, this is done in two phases using {@link WindowContainerTransaction}
- * - setActivityWindowingMode to undefined at beginning of the transaction. without changing
- * the windowing mode of the Task itself. This makes sure the activity render it's final
- * configuration while the Task is still in PiP.
+ * Expands PiP to the previous bounds, this is done in two phases using
+ * {@link WindowContainerTransaction}
+ * - setActivityWindowingMode to either fullscreen or split-secondary at beginning of the
+ * transaction. without changing the windowing mode of the Task itself. This makes sure the
+ * activity render it's final configuration while the Task is still in PiP.
* - setWindowingMode to undefined at the end of transition
* @param animationDurationMs duration in millisecond for the exiting PiP transition
*/
- public void dismissPip(int animationDurationMs) {
+ public void exitPip(int animationDurationMs) {
if (!mInPip || mToken == null) {
- Log.wtf(TAG, "Not allowed to dismissPip in current state"
+ Log.wtf(TAG, "Not allowed to exitPip in current state"
+ " mInPip=" + mInPip + " mToken=" + mToken);
return;
}
+
+ final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
+ final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
+ != mPipBoundsHandler.getDisplayRotation();
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- WindowOrganizer.applyTransaction(wct);
- final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder());
- final int direction = syncWithSplitScreenBounds(destinationBounds)
- ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN;
- scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
- direction, animationDurationMs, null /* updateBoundsCallback */);
- mInPip = false;
+ if (orientationDiffers) {
+ // Don't bother doing an animation if the display rotation differs or if it's in
+ // a non-supported windowing mode
+ wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ WindowOrganizer.applyTransaction(wct);
+ mInPip = false;
+ } else {
+ final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
+ final int direction = syncWithSplitScreenBounds(destinationBounds)
+ ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN
+ : TRANSITION_DIRECTION_TO_FULLSCREEN;
+ final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
+ mLastReportedBounds);
+ tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
+ wct.setActivityWindowingMode(mToken, direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_FULLSCREEN);
+ wct.setBounds(mToken, destinationBounds);
+ wct.setBoundsChangeTransaction(mToken, tx);
+ applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ @Override
+ public void onTransactionReady(int id, SurfaceControl.Transaction t) {
+ t.apply();
+ scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
+ direction, animationDurationMs, null /* updateBoundsCallback */);
+ mInPip = false;
+ }
+ });
+ }
+ }
+
+ /**
+ * Removes PiP immediately.
+ */
+ public void removePip() {
+ if (!mInPip || mToken == null) {
+ Log.wtf(TAG, "Not allowed to removePip in current state"
+ + " mInPip=" + mInPip + " mToken=" + mToken);
+ return;
+ }
+ getUpdateHandler().post(() -> {
+ try {
+ ActivityTaskManager.getService().removeStacksInWindowingModes(
+ new int[]{ WINDOWING_MODE_PINNED });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to remove PiP", e);
+ }
+ });
+ mInitialState.remove(mToken.asBinder());
}
@Override
@@ -277,19 +335,37 @@
mInPip = true;
mLeash = leash;
+ // TODO: Skip enter animation when entering pip from another orientation
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
- mBoundsToRestore.put(mToken.asBinder(), currentBounds);
+ mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
+
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
scheduleAnimateResizePip(currentBounds, destinationBounds,
TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
null /* updateBoundsCallback */);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- mUpdateHandler.post(() -> mPipAnimationController
- .getAnimator(mLeash, destinationBounds, 0f, 1f)
- .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
- .setPipAnimationCallback(mPipAnimationCallback)
- .setDuration(mEnterExitAnimationDuration)
- .start());
+ // If we are fading the PIP in, then we should move the pip to the final location as
+ // soon as possible, but set the alpha immediately since the transaction can take a
+ // while to process
+ final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.setAlpha(mLeash, 0f);
+ tx.apply();
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ wct.setBounds(mToken, destinationBounds);
+ wct.scheduleFinishEnterPip(mToken, destinationBounds);
+ applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ @Override
+ public void onTransactionReady(int id, SurfaceControl.Transaction t) {
+ t.apply();
+ mUpdateHandler.post(() -> mPipAnimationController
+ .getAnimator(mLeash, destinationBounds, 0f, 1f)
+ .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(mEnterExitAnimationDuration)
+ .start());
+ }
+ });
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
} else {
throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType);
@@ -297,7 +373,7 @@
}
/**
- * Note that dismissing PiP is now originated from SystemUI, see {@link #dismissPip(int)}.
+ * Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
* Meanwhile this callback is invoked whenever the task is removed. For instance:
* - as a result of removeStacksInWindowingModes from WM
* - activity itself is died
@@ -411,6 +487,7 @@
// can be initiated in other component, ignore if we are no longer in PIP
return;
}
+
SomeArgs args = SomeArgs.obtain();
args.arg1 = updateBoundsCallback;
args.arg2 = currentBounds;
@@ -449,12 +526,21 @@
* {@link #scheduleResizePip}.
*/
public void scheduleFinishResizePip(Rect destinationBounds) {
+ scheduleFinishResizePip(destinationBounds, null);
+ }
+
+ /**
+ * Same as {@link #scheduleFinishResizePip} but with a callback.
+ */
+ public void scheduleFinishResizePip(Rect destinationBounds,
+ Consumer<Rect> updateBoundsCallback) {
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
.resetScale(tx, mLeash, destinationBounds)
.round(tx, mLeash, mInPip);
- scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, null);
+ scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE,
+ updateBoundsCallback);
}
private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
@@ -509,11 +595,12 @@
throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+ "directly");
}
- // Could happen when dismissPip
+ // Could happen when exitPip
if (mToken == null || mLeash == null) {
Log.w(TAG, "Abort animation, invalid leash");
return;
}
+ mLastReportedBounds.set(destinationBounds);
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
@@ -526,7 +613,7 @@
throw new RuntimeException("Callers should call scheduleUserResizePip() instead of "
+ "this directly");
}
- // Could happen when dismissPip
+ // Could happen when exitPip
if (mToken == null || mLeash == null) {
Log.w(TAG, "Abort animation, invalid leash");
return;
@@ -537,29 +624,43 @@
}
private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
- @PipAnimationController.TransitionDirection int direction) {
+ @PipAnimationController.TransitionDirection int direction,
+ @PipAnimationController.AnimationType int type) {
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+ "directly");
}
mLastReportedBounds.set(destinationBounds);
+ if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
+ return;
+ }
+
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect taskBounds;
- if (isOutPipDirection(direction)) {
+ if (isInPipDirection(direction)) {
+ // If we are animating from fullscreen using a bounds animation, then reset the
+ // activity windowing mode set by WM, and set the task bounds to the final bounds
+ taskBounds = destinationBounds;
+ wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ wct.scheduleFinishEnterPip(mToken, destinationBounds);
+ } else if (isOutPipDirection(direction)) {
// If we are animating to fullscreen, then we need to reset the override bounds
// on the task to ensure that the task "matches" the parent's bounds.
taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
? null : destinationBounds;
- // As for the final windowing mode, simply reset it to undefined.
+ // As for the final windowing mode, simply reset it to undefined and reset the activity
+ // mode set prior to the animation running
wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ if (mSplitDivider != null && direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN) {
+ wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
+ }
} else {
+ // Just a resize in PIP
taskBounds = destinationBounds;
}
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- wct.scheduleFinishEnterPip(mToken, taskBounds);
- } else {
- wct.setBounds(mToken, taskBounds);
- }
+
+ wct.setBounds(mToken, taskBounds);
wct.setBoundsChangeTransaction(mToken, tx);
WindowOrganizer.applyTransaction(wct);
}
@@ -570,17 +671,17 @@
throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
+ "this directly");
}
- // Could happen when dismissPip
+ // Could happen when exitPip
if (mToken == null || mLeash == null) {
Log.w(TAG, "Abort animation, invalid leash");
return;
}
- mUpdateHandler.post(() -> mPipAnimationController
+ mPipAnimationController
.getAnimator(mLeash, currentBounds, destinationBounds)
.setTransitionDirection(direction)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(durationMs)
- .start());
+ .start();
}
private Size getMinimalSize(ActivityInfo activityInfo) {
@@ -609,7 +710,7 @@
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (mSplitDivider == null || !mSplitDivider.inSplitMode()) {
+ if (mSplitDivider == null || !mSplitDivider.isDividerVisible()) {
// bail early if system is not in split screen mode
return false;
}
@@ -621,6 +722,27 @@
}
/**
+ * Dumps internal states.
+ */
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mTaskInfo=" + mTaskInfo);
+ pw.println(innerPrefix + "mToken=" + mToken
+ + " binder=" + (mToken != null ? mToken.asBinder() : null));
+ pw.println(innerPrefix + "mLeash=" + mLeash);
+ pw.println(innerPrefix + "mInPip=" + mInPip);
+ pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
+ pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
+ pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds);
+ pw.println(innerPrefix + "mInitialState:");
+ for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) {
+ pw.println(innerPrefix + " binder=" + e.getKey()
+ + " winConfig=" + e.getValue().windowConfiguration);
+ }
+ }
+
+ /**
* Callback interface for PiP transitions (both from and to PiP mode)
*/
public interface PipTransitionCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
index 84f7e89..f1eef43 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
@@ -101,7 +101,7 @@
result = true;
break;
case AccessibilityNodeInfo.ACTION_EXPAND:
- mMotionHelper.expandPip();
+ mMotionHelper.expandPipToFullscreen();
result = true;
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 0841bb7..64df2ff 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -25,7 +25,6 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -96,7 +95,7 @@
private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
- displayId, fromRotation, toRotation, t);
+ mPipTaskOrganizer.getLastReportedBounds(), displayId, fromRotation, toRotation, t);
if (changed) {
updateMovementBounds(mTmpNormalBounds, true /* fromRotation */,
false /* fromImeAdjustment */, false /* fromShelfAdjustment */);
@@ -140,7 +139,7 @@
!= WINDOWING_MODE_PINNED) {
return;
}
- mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
+ mTouchHandler.getMotionHelper().expandPipToFullscreen(clearedTask /* skipAnimation */);
}
};
@@ -214,7 +213,6 @@
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
mPipBoundsHandler = pipBoundsHandler;
mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
@@ -222,7 +220,7 @@
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
mMenuController = new PipMenuActivityController(context, mMediaController,
mInputConsumerController);
- mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager,
+ mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
floatingContentCoordinator, deviceConfig, pipSnapAlgorithm);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
@@ -237,7 +235,7 @@
try {
mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
- ActivityManager.StackInfo stackInfo = activityTaskManager.getStackInfo(
+ ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null) {
// If SystemUI restart, and it already existed a pinned stack,
@@ -261,7 +259,7 @@
*/
@Override
public void expandPip() {
- mTouchHandler.getMotionHelper().expandPip(false /* skipAnimation */);
+ mTouchHandler.getMotionHelper().expandPipToFullscreen(false /* skipAnimation */);
}
/**
@@ -295,7 +293,7 @@
final boolean changed = mPipBoundsHandler.setShelfHeight(visible, height);
if (changed) {
mTouchHandler.onShelfVisibilityChanged(visible, height);
- updateMovementBounds(mPipBoundsHandler.getLastDestinationBounds(),
+ updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(),
false /* fromRotation */, false /* fromImeAdjustment */,
true /* fromShelfAdjustment */);
}
@@ -378,5 +376,6 @@
mMenuController.dump(pw, innerPrefix);
mTouchHandler.dump(pw, innerPrefix);
mPipBoundsHandler.dump(pw, innerPrefix);
+ mPipTaskOrganizer.dump(pw, innerPrefix);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index ec15dd1..1982227 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -27,7 +27,7 @@
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_DISMISS_FRACTION;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MENU_STATE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MOVEMENT_BOUNDS;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU_WITH_DELAY;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_WILL_RESIZE_MENU;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
@@ -138,9 +138,9 @@
final Bundle data = (Bundle) msg.obj;
showMenu(data.getInt(EXTRA_MENU_STATE),
data.getParcelable(EXTRA_STACK_BOUNDS),
- data.getParcelable(EXTRA_MOVEMENT_BOUNDS),
data.getBoolean(EXTRA_ALLOW_TIMEOUT),
- data.getBoolean(EXTRA_WILL_RESIZE_MENU));
+ data.getBoolean(EXTRA_WILL_RESIZE_MENU),
+ data.getBoolean(EXTRA_SHOW_MENU_WITH_DELAY));
break;
}
case MESSAGE_POKE_MENU:
@@ -177,12 +177,7 @@
private Messenger mToControllerMessenger;
private Messenger mMessenger = new Messenger(mHandler);
- private final Runnable mFinishRunnable = new Runnable() {
- @Override
- public void run() {
- hideMenu();
- }
- };
+ private final Runnable mFinishRunnable = this::hideMenu;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -321,8 +316,8 @@
// Do nothing
}
- private void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
- boolean allowMenuTimeout, boolean resizeMenuOnShow) {
+ private void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean resizeMenuOnShow, boolean withDelay) {
mAllowMenuTimeout = allowMenuTimeout;
if (mMenuState != menuState) {
// Disallow touches if the menu needs to resize while showing, and we are transitioning
@@ -335,7 +330,6 @@
if (mMenuContainerAnimator != null) {
mMenuContainerAnimator.cancel();
}
- notifyMenuStateChange(menuState, resizeMenuOnShow);
mMenuContainerAnimator = new AnimatorSet();
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
@@ -359,7 +353,13 @@
}
});
}
- mMenuContainerAnimator.start();
+ if (withDelay) {
+ // starts the menu container animation after window expansion is completed
+ notifyMenuStateChange(menuState, resizeMenuOnShow, mMenuContainerAnimator::start);
+ } else {
+ notifyMenuStateChange(menuState, resizeMenuOnShow, null /* callback */);
+ mMenuContainerAnimator.start();
+ }
} else {
// If we are already visible, then just start the delayed dismiss and unregister any
// existing input consumers from the previous drag
@@ -382,7 +382,7 @@
if (mMenuState != MENU_STATE_NONE) {
cancelDelayedFinish();
if (notifyMenuVisibility) {
- notifyMenuStateChange(MENU_STATE_NONE, mResize);
+ notifyMenuStateChange(MENU_STATE_NONE, mResize, null /* callback */);
}
mMenuContainerAnimator = new AnimatorSet();
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
@@ -434,10 +434,10 @@
final int menuState = intent.getIntExtra(EXTRA_MENU_STATE, MENU_STATE_NONE);
if (menuState != MENU_STATE_NONE) {
Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
- Rect movementBounds = intent.getParcelableExtra(EXTRA_MOVEMENT_BOUNDS);
boolean allowMenuTimeout = intent.getBooleanExtra(EXTRA_ALLOW_TIMEOUT, true);
boolean willResizeMenu = intent.getBooleanExtra(EXTRA_WILL_RESIZE_MENU, false);
- showMenu(menuState, stackBounds, movementBounds, allowMenuTimeout, willResizeMenu);
+ boolean withDelay = intent.getBooleanExtra(EXTRA_SHOW_MENU_WITH_DELAY, false);
+ showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay);
}
}
@@ -540,13 +540,14 @@
mBackgroundDrawable.setAlpha(alpha);
}
- private void notifyMenuStateChange(int menuState, boolean resize) {
+ private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) {
mMenuState = menuState;
mResize = resize;
Message m = Message.obtain();
m.what = PipMenuActivityController.MESSAGE_MENU_STATE_CHANGED;
m.arg1 = menuState;
m.arg2 = resize ? 1 : 0;
+ m.obj = callback;
sendMessage(m, "Could not notify controller of PIP menu visibility");
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 61ed40d..1608f83 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -60,11 +60,11 @@
public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
public static final String EXTRA_ACTIONS = "actions";
public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
- public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
public static final String EXTRA_MENU_STATE = "menu_state";
+ public static final String EXTRA_SHOW_MENU_WITH_DELAY = "show_menu_with_delay";
public static final int MESSAGE_MENU_STATE_CHANGED = 100;
public static final int MESSAGE_EXPAND_PIP = 101;
@@ -89,7 +89,7 @@
* @param menuState the current state of the menu
* @param resize whether or not to resize the PiP with the state change
*/
- void onPipMenuStateChanged(int menuState, boolean resize);
+ void onPipMenuStateChanged(int menuState, boolean resize, Runnable callback);
/**
* Called when the PIP requested to be expanded.
@@ -130,7 +130,7 @@
case MESSAGE_MENU_STATE_CHANGED: {
int menuState = msg.arg1;
boolean resize = msg.arg2 != 0;
- onMenuStateChanged(menuState, resize);
+ onMenuStateChanged(menuState, resize, (Runnable) msg.obj);
break;
}
case MESSAGE_EXPAND_PIP: {
@@ -155,7 +155,7 @@
// Mark the menu as invisible once the activity finishes as well
if (mToActivityMessenger == null) {
final boolean resize = msg.arg1 != 0;
- onMenuStateChanged(MENU_STATE_NONE, resize);
+ onMenuStateChanged(MENU_STATE_NONE, resize, null /* callback */);
}
break;
}
@@ -247,21 +247,38 @@
// If we haven't requested the start activity, or if it previously took too long to
// start, then start it
startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
- null /* movementBounds */, false /* allowMenuTimeout */,
- false /* resizeMenuOnShow */);
+ false /* allowMenuTimeout */, false /* resizeMenuOnShow */,
+ false /* withDelay */);
}
}
/**
- * Shows the menu activity.
+ * Similar to {@link #showMenu(int, Rect, boolean, boolean)} but only show the menu upon
+ * PiP window transition is finished.
*/
- public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
- boolean allowMenuTimeout, boolean willResizeMenu) {
+ public void showMenuWithDelay(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu) {
+ showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
+ true /* withDelay */);
+ }
+
+ /**
+ * Shows the menu activity immediately.
+ */
+ public void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu) {
+ showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
+ false /* withDelay */);
+ }
+
+ private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu, boolean withDelay) {
if (DEBUG) {
Log.d(TAG, "showMenu() state=" + menuState
+ " hasActivity=" + (mToActivityMessenger != null)
+ " allowMenuTimeout=" + allowMenuTimeout
+ " willResizeMenu=" + willResizeMenu
+ + " withDelay=" + withDelay
+ " callers=\n" + Debug.getCallers(5, " "));
}
@@ -271,9 +288,9 @@
if (stackBounds != null) {
data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
}
- data.putParcelable(EXTRA_MOVEMENT_BOUNDS, movementBounds);
data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
+ data.putBoolean(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
m.obj = data;
@@ -285,8 +302,7 @@
} else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
// If we haven't requested the start activity, or if it previously took too long to
// start, then start it
- startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout,
- willResizeMenu);
+ startMenuActivity(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay);
}
}
@@ -364,7 +380,7 @@
* (ie. when manually expanding or dismissing).
*/
public void hideMenuWithoutResize() {
- onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
+ onMenuStateChanged(MENU_STATE_NONE, false /* resize */, null /* callback */);
}
/**
@@ -388,8 +404,8 @@
/**
* Starts the menu activity on the top task of the pinned stack.
*/
- private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
- boolean allowMenuTimeout, boolean willResizeMenu) {
+ private void startMenuActivity(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu, boolean withDelay) {
try {
StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
@@ -402,12 +418,10 @@
if (stackBounds != null) {
intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
}
- if (movementBounds != null) {
- intent.putExtra(EXTRA_MOVEMENT_BOUNDS, movementBounds);
- }
intent.putExtra(EXTRA_MENU_STATE, menuState);
intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
+ intent.putExtra(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
options.setLaunchTaskId(
pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
@@ -472,14 +486,14 @@
/**
* Handles changes in menu visibility.
*/
- private void onMenuStateChanged(int menuState, boolean resize) {
+ private void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
if (DEBUG) {
Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
+ " menuState=" + menuState + " resize=" + resize);
}
if (menuState != mMenuState) {
- mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize));
+ mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize, callback));
if (menuState == MENU_STATE_FULL) {
// Once visible, start listening for media action changes. This call will trigger
// the menu actions to be updated again.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index b1e4d67..d099597 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -16,15 +16,12 @@
package com.android.systemui.pip.phone;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.IActivityTaskManager;
+import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.RemoteException;
import android.util.Log;
import androidx.dynamicanimation.animation.SpringForce;
@@ -32,7 +29,6 @@
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.FloatProperties;
import com.android.systemui.util.animation.PhysicsAnimator;
@@ -59,12 +55,10 @@
private static final float DEFAULT_FRICTION = 2f;
private final Context mContext;
- private final IActivityTaskManager mActivityTaskManager;
private final PipTaskOrganizer mPipTaskOrganizer;
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
- private FlingAnimationUtils mFlingAnimationUtils;
private final Rect mStableInsets = new Rect();
@@ -123,18 +117,39 @@
*/
private boolean mSpringingToTouch = false;
- public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
- PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
- PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
+ /**
+ * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is
+ * used to show menu activity when the expand animation is completed.
+ */
+ private Runnable mPostPipTransitionCallback;
+
+ private final PipTaskOrganizer.PipTransitionCallback mPipTransitionCallback =
+ new PipTaskOrganizer.PipTransitionCallback() {
+ @Override
+ public void onPipTransitionStarted(ComponentName activity, int direction) {}
+
+ @Override
+ public void onPipTransitionFinished(ComponentName activity, int direction) {
+ if (mPostPipTransitionCallback != null) {
+ mPostPipTransitionCallback.run();
+ mPostPipTransitionCallback = null;
+ }
+ }
+
+ @Override
+ public void onPipTransitionCanceled(ComponentName activity, int direction) {}
+ };
+
+ public PipMotionHelper(Context context, PipTaskOrganizer pipTaskOrganizer,
+ PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
FloatingContentCoordinator floatingContentCoordinator) {
mContext = context;
- mActivityTaskManager = activityTaskManager;
mPipTaskOrganizer = pipTaskOrganizer;
mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
- mFlingAnimationUtils = flingAnimationUtils;
mFloatingContentCoordinator = floatingContentCoordinator;
onConfigurationChanged();
+ mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
}
@NonNull
@@ -242,22 +257,24 @@
/**
* Resizes the pinned stack back to fullscreen.
*/
- void expandPip() {
- expandPip(false /* skipAnimation */);
+ void expandPipToFullscreen() {
+ expandPipToFullscreen(false /* skipAnimation */);
}
/**
* Resizes the pinned stack back to fullscreen.
*/
- void expandPip(boolean skipAnimation) {
+ void expandPipToFullscreen(boolean skipAnimation) {
if (DEBUG) {
- Log.d(TAG, "expandPip: skipAnimation=" + skipAnimation
+ Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
}
cancelAnimations();
mMenuController.hideMenuWithoutResize();
mPipTaskOrganizer.getUpdateHandler().post(() -> {
- mPipTaskOrganizer.dismissPip(skipAnimation ? 0 : EXPAND_STACK_TO_FULLSCREEN_DURATION);
+ mPipTaskOrganizer.exitPip(skipAnimation
+ ? 0
+ : EXPAND_STACK_TO_FULLSCREEN_DURATION);
});
}
@@ -267,18 +284,11 @@
@Override
public void dismissPip() {
if (DEBUG) {
- Log.d(TAG, "dismissPip: callers=\n" + Debug.getCallers(5, " "));
+ Log.d(TAG, "removePip: callers=\n" + Debug.getCallers(5, " "));
}
cancelAnimations();
mMenuController.hideMenuWithoutResize();
- mPipTaskOrganizer.getUpdateHandler().post(() -> {
- try {
- mActivityTaskManager.removeStacksInWindowingModes(
- new int[]{ WINDOWING_MODE_PINNED });
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PiP", e);
- }
- });
+ mPipTaskOrganizer.removePip();
}
/** Sets the movement bounds to use to constrain PIP position animations. */
@@ -328,15 +338,6 @@
}
/**
- * Animates the PiP to the closest snap target.
- */
- void animateToClosestSnapTarget() {
- final Rect newBounds = new Rect();
- mSnapAlgorithm.snapRectToClosestEdge(mBounds, mMovementBounds, newBounds);
- animateToBounds(newBounds, mSpringConfig);
- }
-
- /**
* Animates PIP to the provided bounds, using physics animations and the given spring
* configuration
*/
@@ -375,9 +376,10 @@
* Animates the PiP to the expanded state to show the menu.
*/
float animateToExpandedState(Rect expandedBounds, Rect movementBounds,
- Rect expandedMovementBounds) {
+ Rect expandedMovementBounds, Runnable callback) {
float savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), movementBounds);
mSnapAlgorithm.applySnapFraction(expandedBounds, expandedMovementBounds, savedSnapFraction);
+ mPostPipTransitionCallback = callback;
resizeAndAnimatePipUnchecked(expandedBounds, EXPAND_STACK_TO_MENU_DURATION);
return savedSnapFraction;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index d80f18a..5f0bf56 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -29,6 +29,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
+import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
@@ -45,6 +46,7 @@
import com.android.systemui.util.DeviceConfigProxy;
import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* Helper on top of PipTouchHandler that handles inputs OUTSIDE of the PIP window, which is used to
@@ -66,8 +68,15 @@
private final Point mMinSize = new Point();
private final Rect mLastResizeBounds = new Rect();
private final Rect mLastDownBounds = new Rect();
- private final Rect mTmpBounds = new Rect();
+ private final Rect mDragCornerSize = new Rect();
+ private final Rect mTmpTopLeftCorner = new Rect();
+ private final Rect mTmpTopRightCorner = new Rect();
+ private final Rect mTmpBottomLeftCorner = new Rect();
+ private final Rect mTmpBottomRightCorner = new Rect();
+ private final Rect mDisplayBounds = new Rect();
private final int mDelta;
+ private final Supplier<Rect> mMovementBoundsSupplier;
+ private final Runnable mUpdateMovementBoundsRunnable;
private boolean mAllowGesture;
private boolean mIsAttached;
@@ -82,7 +91,8 @@
public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
- PipTaskOrganizer pipTaskOrganizer) {
+ PipTaskOrganizer pipTaskOrganizer, Supplier<Rect> movementBoundsSupplier,
+ Runnable updateMovementBoundsRunnable) {
final Resources res = context.getResources();
context.getDisplay().getMetrics(mDisplayMetrics);
mDisplayId = context.getDisplayId();
@@ -90,6 +100,8 @@
mPipBoundsHandler = pipBoundsHandler;
mMotionHelper = motionHelper;
mPipTaskOrganizer = pipTaskOrganizer;
+ mMovementBoundsSupplier = movementBoundsSupplier;
+ mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
context.getDisplay().getRealSize(mMaxSize);
mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
@@ -110,6 +122,14 @@
});
}
+ private void resetDragCorners() {
+ mDragCornerSize.set(0, 0, mDelta, mDelta);
+ mTmpTopLeftCorner.set(mDragCornerSize);
+ mTmpTopRightCorner.set(mDragCornerSize);
+ mTmpBottomLeftCorner.set(mDragCornerSize);
+ mTmpBottomRightCorner.set(mDragCornerSize);
+ }
+
private void disposeInputChannel() {
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
@@ -154,34 +174,75 @@
}
}
- private boolean isWithinTouchRegion(int x, int y) {
+ /**
+ * Check whether the current x,y coordinate is within the region in which drag-resize should
+ * start.
+ * This consists of 4 small squares on the 4 corners of the PIP window, a quarter of which
+ * overlaps with the PIP window while the rest goes outside of the PIP window.
+ * _ _ _ _
+ * |_|_|_________|_|_|
+ * |_|_| |_|_|
+ * | PIP |
+ * | WINDOW |
+ * _|_ _|_
+ * |_|_|_________|_|_|
+ * |_|_| |_|_|
+ */
+ public boolean isWithinTouchRegion(int x, int y) {
final Rect currentPipBounds = mMotionHelper.getBounds();
if (currentPipBounds == null) {
return false;
}
+ resetDragCorners();
+ mTmpTopLeftCorner.offset(currentPipBounds.left - mDelta / 2,
+ currentPipBounds.top - mDelta / 2);
+ mTmpTopRightCorner.offset(currentPipBounds.right - mDelta / 2,
+ currentPipBounds.top - mDelta / 2);
+ mTmpBottomLeftCorner.offset(currentPipBounds.left - mDelta / 2,
+ currentPipBounds.bottom - mDelta / 2);
+ mTmpBottomRightCorner.offset(currentPipBounds.right - mDelta / 2,
+ currentPipBounds.bottom - mDelta / 2);
- mTmpBounds.set(currentPipBounds);
- mTmpBounds.inset(-mDelta, -mDelta);
+ mTmpRegion.setEmpty();
+ mTmpRegion.op(mTmpTopLeftCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpTopRightCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpBottomLeftCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpBottomRightCorner, Region.Op.UNION);
- mTmpRegion.set(mTmpBounds);
- mTmpRegion.op(currentPipBounds, Region.Op.DIFFERENCE);
+ return mTmpRegion.contains(x, y);
+ }
- if (mTmpRegion.contains(x, y)) {
- if (x < currentPipBounds.left) {
- mCtrlType |= CTRL_LEFT;
- }
- if (x > currentPipBounds.right) {
- mCtrlType |= CTRL_RIGHT;
- }
- if (y < currentPipBounds.top) {
- mCtrlType |= CTRL_TOP;
- }
- if (y > currentPipBounds.bottom) {
- mCtrlType |= CTRL_BOTTOM;
- }
- return true;
+ private void setCtrlType(int x, int y) {
+ final Rect currentPipBounds = mMotionHelper.getBounds();
+
+ Rect movementBounds = mMovementBoundsSupplier.get();
+ mDisplayBounds.set(movementBounds.left,
+ movementBounds.top,
+ movementBounds.right + currentPipBounds.width(),
+ movementBounds.bottom + currentPipBounds.height());
+
+ if (mTmpTopLeftCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top
+ && currentPipBounds.left != mDisplayBounds.left) {
+ mCtrlType |= CTRL_LEFT;
+ mCtrlType |= CTRL_TOP;
}
- return false;
+ if (mTmpTopRightCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top
+ && currentPipBounds.right != mDisplayBounds.right) {
+ mCtrlType |= CTRL_RIGHT;
+ mCtrlType |= CTRL_TOP;
+ }
+ if (mTmpBottomRightCorner.contains(x, y)
+ && currentPipBounds.bottom != mDisplayBounds.bottom
+ && currentPipBounds.right != mDisplayBounds.right) {
+ mCtrlType |= CTRL_RIGHT;
+ mCtrlType |= CTRL_BOTTOM;
+ }
+ if (mTmpBottomLeftCorner.contains(x, y)
+ && currentPipBounds.bottom != mDisplayBounds.bottom
+ && currentPipBounds.left != mDisplayBounds.left) {
+ mCtrlType |= CTRL_LEFT;
+ mCtrlType |= CTRL_BOTTOM;
+ }
}
private void onMotionEvent(MotionEvent ev) {
@@ -190,6 +251,7 @@
mLastResizeBounds.setEmpty();
mAllowGesture = isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
if (mAllowGesture) {
+ setCtrlType((int) ev.getX(), (int) ev.getY());
mDownPoint.set(ev.getX(), ev.getY());
mLastDownBounds.set(mMotionHelper.getBounds());
}
@@ -214,10 +276,14 @@
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds);
- mMotionHelper.synchronizePinnedStackBounds();
- mCtrlType = CTRL_NONE;
- mAllowGesture = false;
+ mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, (Rect bounds) -> {
+ new Handler(Looper.getMainLooper()).post(() -> {
+ mMotionHelper.synchronizePinnedStackBounds();
+ mUpdateMovementBoundsRunnable.run();
+ mCtrlType = CTRL_NONE;
+ mAllowGesture = false;
+ });
+ });
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index f5c83c1..d0ff2ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -23,7 +23,6 @@
import android.annotation.SuppressLint;
import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -182,13 +181,13 @@
*/
private class PipMenuListener implements PipMenuActivityController.Listener {
@Override
- public void onPipMenuStateChanged(int menuState, boolean resize) {
- setMenuState(menuState, resize);
+ public void onPipMenuStateChanged(int menuState, boolean resize, Runnable callback) {
+ setMenuState(menuState, resize, callback);
}
@Override
public void onPipExpand() {
- mMotionHelper.expandPip();
+ mMotionHelper.expandPipToFullscreen();
}
@Override
@@ -204,13 +203,13 @@
@Override
public void onPipShowMenu() {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
+ true /* allowMenuTimeout */, willResizeMenu());
}
}
@SuppressLint("InflateParams")
public PipTouchHandler(Context context, IActivityManager activityManager,
- IActivityTaskManager activityTaskManager, PipMenuActivityController menuController,
+ PipMenuActivityController menuController,
InputConsumerController inputConsumerController,
PipBoundsHandler pipBoundsHandler,
PipTaskOrganizer pipTaskOrganizer,
@@ -228,14 +227,15 @@
mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
2.5f);
mGesture = new DefaultPipTouchGesture();
- mMotionHelper = new PipMotionHelper(mContext, activityTaskManager, pipTaskOrganizer,
- mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator);
+ mMotionHelper = new PipMotionHelper(mContext, pipTaskOrganizer, mMenuController,
+ mSnapAlgorithm, floatingContentCoordinator);
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
- deviceConfig, pipTaskOrganizer);
+ deviceConfig, pipTaskOrganizer, this::getMovementBounds,
+ this::updateMovementBounds);
mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
- () -> mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */, willResizeMenu()));
+ () -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
+ true /* allowMenuTimeout */, willResizeMenu()));
Resources res = context.getResources();
mExpandedShortestEdgeSize = res.getDimensionPixelSize(
@@ -322,7 +322,7 @@
// Only show the menu if the user isn't currently interacting with the PiP
if (!mTouchState.isUserInteracting()) {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, false /* allowMenuTimeout */, willResizeMenu());
+ false /* allowMenuTimeout */, willResizeMenu());
}
}
@@ -358,7 +358,7 @@
if (mShowPipMenuOnAnimationEnd) {
mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */, false /* willResizeMenu */);
+ true /* allowMenuTimeout */, false /* willResizeMenu */);
mShowPipMenuOnAnimationEnd = false;
}
}
@@ -424,7 +424,7 @@
// If this is from an IME or shelf adjustment, then we should move the PiP so that it is not
// occluded by the IME or shelf.
- if (fromImeAdjustment || fromShelfAdjustment || fromDisplayRotationChanged) {
+ if (fromImeAdjustment || fromShelfAdjustment) {
if (mTouchState.isUserInteracting()) {
// Defer the update of the current movement bounds until after the user finishes
// touching the screen
@@ -557,7 +557,7 @@
private void onAccessibilityShowMenu() {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
+ true /* allowMenuTimeout */, willResizeMenu());
}
private boolean handleTouchEvent(InputEvent inputEvent) {
@@ -572,6 +572,11 @@
MotionEvent ev = (MotionEvent) inputEvent;
+
+ if (mPipResizeGestureHandler.isWithinTouchRegion((int) ev.getX(), (int) ev.getY())) {
+ return true;
+ }
+
if (mMagnetizedPip.maybeConsumeMotionEvent(ev)) {
// If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
// to the touch state. Touch state needs a DOWN event in order to later process MOVE
@@ -628,8 +633,7 @@
// Let's not enable menu show/hide for a11y services.
if (!mAccessibilityManager.isTouchExplorationEnabled()) {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, false /* allowMenuTimeout */,
- false /* willResizeMenu */);
+ false /* allowMenuTimeout */, false /* willResizeMenu */);
}
case MotionEvent.ACTION_HOVER_MOVE: {
if (!shouldDeliverToMenu && !mSendingHoverAccessibilityEvents) {
@@ -713,7 +717,7 @@
/**
* Sets the menu visibility.
*/
- private void setMenuState(int menuState, boolean resize) {
+ private void setMenuState(int menuState, boolean resize, Runnable callback) {
if (mMenuState == menuState && !resize) {
return;
}
@@ -727,7 +731,7 @@
mResizedBounds.set(mMotionHelper.getBounds());
Rect expandedBounds = new Rect(mExpandedBounds);
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
- mMovementBounds, mExpandedMovementBounds);
+ mMovementBounds, mExpandedMovementBounds, callback);
}
} else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
// Try and restore the PiP to the closest edge, using the saved snap fraction
@@ -810,6 +814,7 @@
private class DefaultPipTouchGesture extends PipTouchGesture {
private final Point mStartPosition = new Point();
private final PointF mDelta = new PointF();
+ private boolean mShouldHideMenuAfterFling;
@Override
public void onDown(PipTouchState touchState) {
@@ -885,39 +890,30 @@
final PointF vel = touchState.getVelocity();
final float velocity = PointF.length(vel.x, vel.y);
- final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond();
if (touchState.isDragging()) {
- Runnable endAction = null;
if (mMenuState != MENU_STATE_NONE) {
// If the menu is still visible, then just poke the menu so that
// it will timeout after the user stops touching it
mMenuController.showMenu(mMenuState, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
- } else {
- // If the menu is not visible, then we can still be showing the activity for the
- // dismiss overlay, so just finish it after the animation completes
- endAction = mMenuController::hideMenu;
+ true /* allowMenuTimeout */, willResizeMenu());
}
+ mShouldHideMenuAfterFling = mMenuState == MENU_STATE_NONE;
- if (isFling) {
- mMotionHelper.flingToSnapTarget(vel.x, vel.y,
- PipTouchHandler.this::updateDismissFraction /* updateAction */,
- endAction /* endAction */);
- } else {
- mMotionHelper.animateToClosestSnapTarget();
- }
+ mMotionHelper.flingToSnapTarget(vel.x, vel.y,
+ PipTouchHandler.this::updateDismissFraction /* updateAction */,
+ this::flingEndAction /* endAction */);
} else if (mTouchState.isDoubleTap()) {
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
setTouchEnabled(false);
- mMotionHelper.expandPip();
+ mMotionHelper.expandPipToFullscreen();
} else if (mMenuState != MENU_STATE_FULL) {
if (!mTouchState.isWaitingForDoubleTap()) {
// User has stalled long enough for this not to be a drag or a double tap, just
// expand the menu
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
+ true /* allowMenuTimeout */, willResizeMenu());
} else {
// Next touch event _may_ be the second tap for the double-tap, schedule a
// fallback runnable to trigger the menu if no touch event occurs before the
@@ -927,6 +923,15 @@
}
return true;
}
+
+ private void flingEndAction() {
+ mTouchState.setAllowTouches(true);
+ if (mShouldHideMenuAfterFling) {
+ // If the menu is not visible, then we can still be showing the activity for the
+ // dismiss overlay, so just finish it after the animation completes
+ mMenuController.hideMenu();
+ }
+ }
};
/**
@@ -943,6 +948,10 @@
isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
}
+ private Rect getMovementBounds() {
+ return mMovementBounds;
+ }
+
/**
* @return whether the menu will resize as a part of showing the full menu.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index f49732d..6282236 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -468,7 +468,7 @@
mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration,
null);
} else {
- mPipTaskOrganizer.dismissPip(mResizeAnimationDuration);
+ mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index c8cf02a..10b04c0 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -302,13 +302,15 @@
}
private void showAutoSaverSuggestionNotification() {
+ final CharSequence message = mContext.getString(R.string.auto_saver_text);
final Notification.Builder nb =
new Notification.Builder(mContext, NotificationChannels.HINTS)
.setSmallIcon(R.drawable.ic_power_saver)
.setWhen(0)
.setShowWhen(false)
.setContentTitle(mContext.getString(R.string.auto_saver_title))
- .setContentText(mContext.getString(R.string.auto_saver_text));
+ .setStyle(new Notification.BigTextStyle().bigText(message))
+ .setContentText(message);
nb.setContentIntent(pendingBroadcast(ACTION_ENABLE_AUTO_SAVER));
nb.setDeleteIntent(pendingBroadcast(ACTION_DISMISS_AUTO_SAVER_SUGGESTION));
nb.addAction(0,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
index c5ae3ab..40d317c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
@@ -117,7 +117,7 @@
it.tileView.measure(exactly(smallTileSize), exactly(smallTileSize))
}
- val height = twoLineHeight
+ val height = twoLineHeight + paddingBottom + paddingTop
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index b157f4b..aaff9ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -152,15 +152,33 @@
}
@Override
+ public void fakeDragBy(float xOffset) {
+ try {
+ super.fakeDragBy(xOffset);
+ // Keep on drawing until the animation has finished.
+ postInvalidateOnAnimation();
+ } catch (NullPointerException e) {
+ Log.e(TAG, "FakeDragBy called before begin", e);
+ // If we were trying to fake drag, it means we just added a new tile to the last
+ // page, so animate there.
+ final int lastPageNumber = mPages.size() - 1;
+ post(() -> {
+ setCurrentItem(lastPageNumber, true);
+ if (mBounceAnimatorSet != null) {
+ mBounceAnimatorSet.start();
+ }
+ setOffscreenPageLimit(1);
+ });
+ }
+ }
+
+ @Override
public void computeScroll() {
if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
if (!isFakeDragging()) {
beginFakeDrag();
}
fakeDragBy(getScrollX() - mScroller.getCurrX());
- // Keep on drawing until the animation has finished.
- postInvalidateOnAnimation();
- return;
} else if (isFakeDragging()) {
endFakeDrag();
mBounceAnimatorSet.start();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a0ea7fa..ce00229 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -269,14 +269,6 @@
count++;
}
-
- if (Utils.useQsMediaPlayer(mQsPanel.getContext())) {
- View qsMediaView = mQsPanel.getMediaPanel();
- View qqsMediaView = mQuickQsPanel.getMediaPlayer().getView();
- translationXBuilder.addFloat(qsMediaView, "alpha", 0, 1);
- translationXBuilder.addFloat(qqsMediaView, "alpha", 1, 0);
- }
-
if (mAllowFancy) {
// Make brightness appear static position and alpha in through second half.
View brightness = mQsPanel.getBrightnessView();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index be8a8fd..6b0775f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -42,7 +42,7 @@
private QuickStatusBarHeader mHeader;
private float mQsExpansion;
private QSCustomizer mQSCustomizer;
- private View mQSFooter;
+ private View mDragHandle;
private View mBackground;
private View mBackgroundGradient;
@@ -62,7 +62,7 @@
mQSDetail = findViewById(R.id.qs_detail);
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
- mQSFooter = findViewById(R.id.qs_footer);
+ mDragHandle = findViewById(R.id.qs_drag_handle_view);
mBackground = findViewById(R.id.quick_settings_background);
mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
@@ -167,8 +167,8 @@
int height = calculateContainerHeight();
setBottom(getTop() + height);
mQSDetail.setBottom(getTop() + height);
- // Pin QS Footer to the bottom of the panel.
- mQSFooter.setTranslationY(height - mQSFooter.getHeight());
+ // Pin the drag handle to the bottom of the panel.
+ mDragHandle.setTranslationY(height - mDragHandle.getHeight());
mBackground.setTop(mQSPanel.getTop());
mBackground.setBottom(height);
}
@@ -192,13 +192,13 @@
public void setExpansion(float expansion) {
mQsExpansion = expansion;
+ mDragHandle.setAlpha(1.0f - expansion);
updateExpansion();
}
private void setMargins() {
setMargins(mQSDetail);
setMargins(mBackground);
- setMargins(mQSFooter);
mQSPanel.setMargins(mSideMargins);
mHeader.setMargins(mSideMargins);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 5de6d1c..fc8e36f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -98,7 +98,6 @@
private TouchAnimator mSettingsCogAnimator;
private View mActionsContainer;
- private View mDragHandle;
private OnClickListener mExpandClickListener;
@@ -146,7 +145,6 @@
mMultiUserSwitch = findViewById(R.id.multi_user_switch);
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
- mDragHandle = findViewById(R.id.qs_drag_handle_view);
mActionsContainer = findViewById(R.id.qs_footer_actions_container);
mEditContainer = findViewById(R.id.qs_footer_actions_edit_container);
@@ -219,7 +217,6 @@
return new TouchAnimator.Builder()
.addFloat(mActionsContainer, "alpha", 0, 1)
.addFloat(mEditContainer, "alpha", 0, 1)
- .addFloat(mDragHandle, "alpha", 1, 0, 0)
.addFloat(mPageIndicator, "alpha", 0, 1)
.setStartDelay(0.15f)
.build();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 5b09267..865fd07 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -37,6 +37,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.R.id;
+import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.customize.QSCustomizer;
@@ -47,6 +48,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.InjectionInflationController;
import com.android.systemui.util.LifecycleFragment;
+import com.android.systemui.util.Utils;
import javax.inject.Inject;
@@ -91,6 +93,7 @@
*/
private int mState;
private QSContainerImplController mQSContainerImplController;
+ private int[] mTmpLocation = new int[2];
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -377,8 +380,7 @@
mLastKeyguardAndExpanded = onKeyguardAndExpanded;
boolean fullyExpanded = expansion == 1;
- int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
- + mFooter.getHeight();
+ int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom();
float panelTranslationY = translationScaleY * heightDiff;
// Let the views animate their contents correctly by giving them the necessary context.
@@ -404,6 +406,32 @@
if (mQSAnimator != null) {
mQSAnimator.setPosition(expansion);
}
+ updateMediaPositions();
+ }
+
+ private void updateMediaPositions() {
+ if (Utils.useQsMediaPlayer(getContext())) {
+ mContainer.getLocationOnScreen(mTmpLocation);
+ float absoluteBottomPosition = mTmpLocation[1] + mContainer.getHeight();
+ pinToBottom(absoluteBottomPosition, mQSPanel.getMediaHost());
+ pinToBottom(absoluteBottomPosition - mHeader.getPaddingBottom(),
+ mHeader.getHeaderQsPanel().getMediaHost());
+ }
+ }
+
+ private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost) {
+ View hostView = mediaHost.getHostView();
+ if (mLastQSExpansion > 0) {
+ ViewGroup.MarginLayoutParams params =
+ (ViewGroup.MarginLayoutParams) hostView.getLayoutParams();
+ float targetPosition = absoluteBottomPosition - params.bottomMargin
+ - hostView.getHeight();
+ float currentPosition = mediaHost.getCurrentState().getBoundsOnScreen().top
+ - hostView.getTranslationY();
+ hostView.setTranslationY(targetPosition - currentPosition);
+ } else {
+ hostView.setTranslationY(0);
+ }
}
private boolean headerWillBeAnimating() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
deleted file mode 100644
index e76cd51..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ /dev/null
@@ -1,276 +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.qs;
-
-import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.media.MediaDescription;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import com.android.settingslib.media.LocalMediaManager;
-import com.android.systemui.R;
-import com.android.systemui.media.MediaControlPanel;
-import com.android.systemui.media.SeekBarObserver;
-import com.android.systemui.media.SeekBarViewModel;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-
-import java.util.concurrent.Executor;
-
-/**
- * Single media player for carousel in QSPanel
- */
-public class QSMediaPlayer extends MediaControlPanel {
-
- private static final String TAG = "QSMediaPlayer";
-
- // Button IDs for QS controls
- static final int[] QS_ACTION_IDS = {
- R.id.action0,
- R.id.action1,
- R.id.action2,
- R.id.action3,
- R.id.action4
- };
-
- private final QSPanel mParent;
- private final Executor mForegroundExecutor;
- private final DelayableExecutor mBackgroundExecutor;
- private final SeekBarViewModel mSeekBarViewModel;
- private final SeekBarObserver mSeekBarObserver;
- private String mPackageName;
-
- /**
- * Initialize quick shade version of player
- * @param context
- * @param parent
- * @param routeManager Provides information about device
- * @param foregroundExecutor
- * @param backgroundExecutor
- * @param activityStarter
- */
- public QSMediaPlayer(Context context, ViewGroup parent, LocalMediaManager routeManager,
- Executor foregroundExecutor, DelayableExecutor backgroundExecutor,
- ActivityStarter activityStarter) {
- super(context, parent, routeManager, R.layout.qs_media_panel, QS_ACTION_IDS,
- foregroundExecutor, backgroundExecutor, activityStarter);
- mParent = (QSPanel) parent;
- mForegroundExecutor = foregroundExecutor;
- mBackgroundExecutor = backgroundExecutor;
- mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor);
- mSeekBarObserver = new SeekBarObserver(getView());
- // Can't use the viewAttachLifecycle of media player because remove/add is used to adjust
- // priority of players. As soon as it is removed, the lifecycle will end and the seek bar
- // will stop updating. So, use the lifecycle of the parent instead.
- mSeekBarViewModel.getProgress().observe(viewAttachLifecycle(parent), mSeekBarObserver);
- SeekBar bar = getView().findViewById(R.id.media_progress_bar);
- bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener());
- bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener());
- }
-
- /**
- * Add a media panel view based on a media description. Used for resumption
- * @param description
- * @param iconColor
- * @param bgColor
- * @param contentIntent
- * @param pkgName
- */
- public void setMediaSession(MediaSession.Token token, MediaDescription description,
- int iconColor, int bgColor, PendingIntent contentIntent, String pkgName) {
- mPackageName = pkgName;
- PackageManager pm = getContext().getPackageManager();
- Drawable icon = null;
- CharSequence appName = pkgName.substring(pkgName.lastIndexOf("."));
- try {
- icon = pm.getApplicationIcon(pkgName);
- appName = pm.getApplicationLabel(pm.getApplicationInfo(pkgName, 0));
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Error getting package information", e);
- }
-
- // Set what we can normally
- super.setMediaSession(token, icon, null, iconColor, bgColor, contentIntent,
- appName.toString(), null);
-
- // Then add info from MediaDescription
- ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
- if (albumView != null) {
- // Resize art in a background thread
- mBackgroundExecutor.execute(() -> processAlbumArt(description, albumView));
- }
-
- // Song name
- TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
- CharSequence songName = description.getTitle();
- titleText.setText(songName);
- titleText.setTextColor(iconColor);
-
- // Artist name (not in mini player)
- TextView artistText = mMediaNotifView.findViewById(R.id.header_artist);
- if (artistText != null) {
- CharSequence artistName = description.getSubtitle();
- artistText.setText(artistName);
- artistText.setTextColor(iconColor);
- }
-
- initLongPressMenu(iconColor);
-
- // Set buttons to resume state
- resetButtons();
- }
-
- /**
- * Update media panel view for the given media session
- * @param token token for this media session
- * @param icon app notification icon
- * @param largeIcon notification's largeIcon, used as a fallback for album art
- * @param iconColor foreground color (for text, icons)
- * @param bgColor background color
- * @param actionsContainer a LinearLayout containing the media action buttons
- * @param contentIntent Intent to send when user taps on player
- * @param appName Application title
- * @param key original notification's key
- */
- public void setMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
- int iconColor, int bgColor, View actionsContainer, PendingIntent contentIntent,
- String appName, String key) {
-
- super.setMediaSession(token, icon, largeIcon, iconColor, bgColor, contentIntent, appName,
- key);
-
- // Media controls
- if (actionsContainer != null) {
- LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
- int i = 0;
- for (; i < parentActionsLayout.getChildCount() && i < QS_ACTION_IDS.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(QS_ACTION_IDS[i]);
- ImageButton thatBtn = parentActionsLayout.findViewById(NOTIF_ACTION_IDS[i]);
- if (thatBtn == null || thatBtn.getDrawable() == null
- || thatBtn.getVisibility() != View.VISIBLE) {
- thisBtn.setVisibility(View.GONE);
- continue;
- }
-
- Drawable thatIcon = thatBtn.getDrawable();
- thisBtn.setImageDrawable(thatIcon.mutate());
- thisBtn.setVisibility(View.VISIBLE);
- thisBtn.setOnClickListener(v -> {
- Log.d(TAG, "clicking on other button");
- thatBtn.performClick();
- });
- }
-
- // Hide any unused buttons
- for (; i < QS_ACTION_IDS.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(QS_ACTION_IDS[i]);
- thisBtn.setVisibility(View.GONE);
- }
- }
-
- // Seek Bar
- final MediaController controller = new MediaController(getContext(), token);
- mBackgroundExecutor.execute(
- () -> mSeekBarViewModel.updateController(controller, iconColor));
-
- initLongPressMenu(iconColor);
- }
-
- private void initLongPressMenu(int iconColor) {
- // Set up long press menu
- View guts = mMediaNotifView.findViewById(R.id.media_guts);
- View options = mMediaNotifView.findViewById(R.id.qs_media_controls_options);
- options.setMinimumHeight(guts.getHeight());
-
- View clearView = options.findViewById(R.id.remove);
- clearView.setOnClickListener(b -> {
- removePlayer();
- });
- ImageView removeIcon = options.findViewById(R.id.remove_icon);
- removeIcon.setImageTintList(ColorStateList.valueOf(iconColor));
- TextView removeText = options.findViewById(R.id.remove_text);
- removeText.setTextColor(iconColor);
-
- TextView cancelView = options.findViewById(R.id.cancel);
- cancelView.setTextColor(iconColor);
- cancelView.setOnClickListener(b -> {
- options.setVisibility(View.GONE);
- guts.setVisibility(View.VISIBLE);
- });
- // ... but don't enable it yet, and make sure is reset when the session is updated
- mMediaNotifView.setOnLongClickListener(null);
- options.setVisibility(View.GONE);
- guts.setVisibility(View.VISIBLE);
- }
-
- @Override
- protected void resetButtons() {
- super.resetButtons();
- mSeekBarViewModel.clearController();
- View guts = mMediaNotifView.findViewById(R.id.media_guts);
- View options = mMediaNotifView.findViewById(R.id.qs_media_controls_options);
-
- mMediaNotifView.setOnLongClickListener(v -> {
- // Replace player view with close/cancel view
- guts.setVisibility(View.GONE);
- options.setVisibility(View.VISIBLE);
- return true; // consumed click
- });
- }
-
- /**
- * Sets the listening state of the player.
- *
- * Should be set to true when the QS panel is open. Otherwise, false. This is a signal to avoid
- * unnecessary work when the QS panel is closed.
- *
- * @param listening True when player should be active. Otherwise, false.
- */
- public void setListening(boolean listening) {
- mSeekBarViewModel.setListening(listening);
- }
-
- @Override
- public void removePlayer() {
- Log.d(TAG, "removing player from parent: " + mParent);
- // Ensure this happens on the main thread (could happen in QSMediaBrowser callback)
- mForegroundExecutor.execute(() -> mParent.removeMediaPlayer(QSMediaPlayer.this));
- }
-
- @Override
- public String getMediaPlayerPackage() {
- if (getController() == null) {
- return mPackageName;
- }
- return super.getMediaPlayerPackage();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index e8f6c96..5e3e438 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -21,7 +21,6 @@
import static com.android.systemui.util.Utils.useQsMediaPlayer;
import android.annotation.Nullable;
-import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -30,44 +29,33 @@
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.media.MediaDescription;
-import android.media.session.MediaSession;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.UserHandle;
import android.os.UserManager;
-import android.service.notification.StatusBarNotification;
import android.service.quicksettings.Tile;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.settingslib.Utils;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.media.InfoMediaManager;
-import com.android.settingslib.media.LocalMediaManager;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaControlPanel;
-import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
@@ -77,20 +65,15 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSliderView;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -108,21 +91,13 @@
protected final Context mContext;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private final BroadcastDispatcher mBroadcastDispatcher;
+ protected final MediaHost mMediaHost;
private String mCachedSpecs = "";
protected final View mBrightnessView;
private final H mHandler = new H();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final QSTileRevealController mQsTileRevealController;
- private final LinearLayout mMediaCarousel;
- private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>();
- private final LocalBluetoothManager mLocalBluetoothManager;
- private final Executor mForegroundExecutor;
- private final DelayableExecutor mBackgroundExecutor;
- private boolean mUpdateCarousel = false;
- private ActivityStarter mActivityStarter;
- private NotificationEntryManager mNotificationEntryManager;
-
protected boolean mExpanded;
protected boolean mListening;
@@ -158,15 +133,6 @@
}
};
- private final NotificationEntryListener mNotificationEntryListener =
- new NotificationEntryListener() {
- @Override
- public void onEntryRemoved(NotificationEntry entry, NotificationVisibility visibility,
- boolean removedByUser, int reason) {
- checkToRemoveMediaNotification(entry);
- }
- };
-
@Inject
public QSPanel(
@Named(VIEW_CONTEXT) Context context,
@@ -174,23 +140,15 @@
DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher,
QSLogger qsLogger,
- @Main Executor foregroundExecutor,
- @Background DelayableExecutor backgroundExecutor,
- @Nullable LocalBluetoothManager localBluetoothManager,
- ActivityStarter activityStarter,
- NotificationEntryManager entryManager,
+ MediaHost mediaHost,
UiEventLogger uiEventLogger
) {
super(context, attrs);
+ mMediaHost = mediaHost;
mContext = context;
mQSLogger = qsLogger;
mDumpManager = dumpManager;
- mForegroundExecutor = foregroundExecutor;
- mBackgroundExecutor = backgroundExecutor;
- mLocalBluetoothManager = localBluetoothManager;
mBroadcastDispatcher = broadcastDispatcher;
- mActivityStarter = activityStarter;
- mNotificationEntryManager = entryManager;
mUiEventLogger = uiEventLogger;
setOrientation(VERTICAL);
@@ -210,16 +168,6 @@
addDivider();
- // Add media carousel
- if (useQsMediaPlayer(context)) {
- HorizontalScrollView mediaScrollView = (HorizontalScrollView) LayoutInflater.from(
- mContext).inflate(R.layout.media_carousel, this, false);
- mMediaCarousel = mediaScrollView.findViewById(R.id.media_carousel);
- addView(mediaScrollView, 0);
- } else {
- mMediaCarousel = null;
- }
-
mFooter = new QSSecurityFooter(this, context);
addView(mFooter.getView());
@@ -230,145 +178,39 @@
}
@Override
- public void onVisibilityAggregated(boolean isVisible) {
- super.onVisibilityAggregated(isVisible);
- if (!isVisible && mUpdateCarousel) {
- for (QSMediaPlayer player : mMediaPlayers) {
- if (player.isPlaying()) {
- LayoutParams lp = (LayoutParams) player.getView().getLayoutParams();
- mMediaCarousel.removeView(player.getView());
- mMediaCarousel.addView(player.getView(), 0, lp);
- ((HorizontalScrollView) mMediaCarousel.getParent()).fullScroll(View.FOCUS_LEFT);
- mUpdateCarousel = false;
- break;
- }
- }
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ // Add media carousel at the end
+ if (useQsMediaPlayer(getContext())) {
+ addMediaHostView();
}
}
- /**
- * Add or update a player for the associated media session
- * @param token
- * @param icon
- * @param largeIcon
- * @param iconColor
- * @param bgColor
- * @param actionsContainer
- * @param notif
- * @param key
- */
- public void addMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
- int iconColor, int bgColor, View actionsContainer, StatusBarNotification notif,
- String key) {
- if (!useQsMediaPlayer(mContext)) {
- // Shouldn't happen, but just in case
- Log.e(TAG, "Tried to add media session without player!");
- return;
- }
- if (token == null) {
- Log.e(TAG, "Media session token was null!");
- return;
- }
-
- String packageName = notif.getPackageName();
- QSMediaPlayer player = findMediaPlayer(packageName, token, key);
-
- int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width);
- int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
- LayoutParams lp = new LayoutParams(playerWidth, ViewGroup.LayoutParams.MATCH_PARENT);
- lp.setMarginStart(padding);
- lp.setMarginEnd(padding);
-
- if (player == null) {
- Log.d(TAG, "creating new player for " + packageName);
- // Set up listener for device changes
- // TODO: integrate with MediaTransferManager?
- InfoMediaManager imm = new InfoMediaManager(mContext, notif.getPackageName(),
- notif.getNotification(), mLocalBluetoothManager);
- LocalMediaManager routeManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
- imm, notif.getPackageName());
-
- player = new QSMediaPlayer(mContext, this, routeManager, mForegroundExecutor,
- mBackgroundExecutor, mActivityStarter);
- player.setListening(mListening);
- if (player.isPlaying()) {
- mMediaCarousel.addView(player.getView(), 0, lp); // add in front
- } else {
- mMediaCarousel.addView(player.getView(), lp); // add at end
- }
- mMediaPlayers.add(player);
- } else if (player.isPlaying()) {
- mUpdateCarousel = true;
- }
-
- Log.d(TAG, "setting player session");
- String appName = Notification.Builder.recoverBuilder(getContext(), notif.getNotification())
- .loadHeaderAppName();
- player.setMediaSession(token, icon, largeIcon, iconColor, bgColor, actionsContainer,
- notif.getNotification().contentIntent, appName, key);
-
- if (mMediaPlayers.size() > 0) {
- ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
- }
- }
-
- /**
- * Check for an existing media player using the given information
- * @param packageName
- * @param token
- * @param key
- * @return a player, or null if no match found
- */
- private QSMediaPlayer findMediaPlayer(String packageName, MediaSession.Token token,
- String key) {
- for (QSMediaPlayer player : mMediaPlayers) {
- if (player.getKey() == null || key == null) {
- // No notification key = loaded via mediabrowser, so just match on package
- if (packageName.equals(player.getMediaPlayerPackage())) {
- Log.d(TAG, "Found matching resume player by package: " + packageName);
- return player;
- }
- } else if (player.getMediaSessionToken().equals(token)) {
- Log.d(TAG, "Found matching player by token " + packageName);
- return player;
- } else if (packageName.equals(player.getMediaPlayerPackage())
- && key.equals(player.getKey())) {
- // Also match if it's the same package and notification key
- Log.d(TAG, "Found matching player by package " + packageName + ", " + key);
- return player;
- }
- }
- return null;
- }
-
- protected View getMediaPanel() {
- return mMediaCarousel;
- }
-
- /**
- * Remove the media player from the carousel
- * @param player Player to remove
- * @return true if removed, false if player was not found
- */
- protected boolean removeMediaPlayer(QSMediaPlayer player) {
- // Remove from list
- if (!mMediaPlayers.remove(player)) {
- return false;
- }
-
- // Check if we need to collapse the carousel now
- mMediaCarousel.removeView(player.getView());
- if (mMediaPlayers.size() == 0) {
- ((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
- }
- return true;
+ protected void addMediaHostView() {
+ mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
+ mMediaHost.setExpansion(1.0f);
+ mMediaHost.setShowsOnlyActiveMedia(false);
+ ViewGroup hostView = mMediaHost.getHostView();
+ addView(hostView);
+ int sidePaddings = getResources().getDimensionPixelSize(
+ R.dimen.quick_settings_side_margins);
+ int bottomPadding = getResources().getDimensionPixelSize(
+ R.dimen.quick_settings_expanded_bottom_margin);
+ MarginLayoutParams layoutParams = (MarginLayoutParams) hostView.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.bottomMargin = bottomPadding;
+ hostView.setLayoutParams(layoutParams);
+ hostView.setPadding(sidePaddings, hostView.getPaddingTop(), sidePaddings,
+ hostView.getPaddingBottom());
}
private final QSMediaBrowser.Callback mMediaBrowserCallback = new QSMediaBrowser.Callback() {
@Override
public void addTrack(MediaDescription desc, ComponentName component,
QSMediaBrowser browser) {
- if (component == null) {
+ // TODO: Fix Resumption b/156104922
+/* if (component == null) {
Log.e(TAG, "Component cannot be null");
return;
}
@@ -404,7 +246,7 @@
int iconColor = Color.DKGRAY;
int bgColor = Color.LTGRAY;
player.setMediaSession(token, desc, iconColor, bgColor, browser.getAppIntent(),
- pkgName);
+ pkgName);*/
}
};
@@ -441,27 +283,6 @@
mHasLoadedMediaControls = true;
}
- private void checkToRemoveMediaNotification(NotificationEntry entry) {
- if (!useQsMediaPlayer(mContext)) {
- return;
- }
-
- if (!entry.isMediaNotification()) {
- return;
- }
-
- // If this entry corresponds to an existing set of controls, clear the controls
- // This will handle apps that use an action to clear their notification
- for (QSMediaPlayer p : mMediaPlayers) {
- if (p.getKey() != null && p.getKey().equals(entry.getKey())) {
- Log.d(TAG, "Clearing controls since notification removed " + entry.getKey());
- p.clearControls();
- return;
- }
- }
- Log.d(TAG, "Media notification removed but no player found " + entry.getKey());
- }
-
protected void addDivider() {
mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
@@ -482,7 +303,11 @@
int numChildren = getChildCount();
for (int i = 0; i < numChildren; i++) {
View child = getChildAt(i);
- if (child.getVisibility() != View.GONE) height += child.getMeasuredHeight();
+ if (child.getVisibility() != View.GONE) {
+ height += child.getMeasuredHeight();
+ MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
+ height += layoutParams.topMargin + layoutParams.bottomMargin;
+ }
}
setMeasuredDimension(getMeasuredWidth(), height);
}
@@ -528,7 +353,6 @@
loadMediaResumptionControls();
}
}
- mNotificationEntryManager.addNotificationEntryListener(mNotificationEntryListener);
}
@Override
@@ -545,7 +369,6 @@
}
mDumpManager.unregisterDumpable(getDumpableTag());
mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
- mNotificationEntryManager.removeNotificationEntryListener(mNotificationEntryListener);
super.onDetachedFromWindow();
}
@@ -724,9 +547,6 @@
if (mListening) {
refreshAllTiles();
}
- for (QSMediaPlayer player : mMediaPlayers) {
- player.setListening(mListening);
- }
}
private String getTilesSpecs() {
@@ -1027,6 +847,10 @@
}
}
+ public MediaHost getMediaHost() {
+ return mMediaHost;
+ }
+
private class H extends Handler {
private static final int SHOW_DETAIL = 1;
private static final int SET_TILE_VISIBILITY = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 54a928d..4008918 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -339,13 +339,18 @@
changeTileSpecs(tileSpecs-> !tileSpecs.contains(spec) && tileSpecs.add(spec));
}
+ private void saveTilesToSettings(List<String> tileSpecs) {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(), TILES_SETTING,
+ TextUtils.join(",", tileSpecs), null /* tag */,
+ false /* default */, mCurrentUser, true /* overrideable by restore */);
+ }
+
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- TILES_SETTING, ActivityManager.getCurrentUser());
+ TILES_SETTING, mCurrentUser);
final List<String> tileSpecs = loadTileSpecs(mContext, setting);
if (changeFunction.test(tileSpecs)) {
- Settings.Secure.putStringForUser(mContext.getContentResolver(), TILES_SETTING,
- TextUtils.join(",", tileSpecs), ActivityManager.getCurrentUser());
+ saveTilesToSettings(tileSpecs);
}
}
@@ -375,7 +380,7 @@
Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
mContext, mServices, new Tile(), intent,
- new UserHandle(ActivityManager.getCurrentUser()),
+ new UserHandle(mCurrentUser),
mBroadcastDispatcher);
lifecycleManager.onStopListening();
lifecycleManager.onTileRemoved();
@@ -384,8 +389,7 @@
}
}
if (DEBUG) Log.d(TAG, "saveCurrentTiles " + newTiles);
- Secure.putStringForUser(getContext().getContentResolver(), QSTileHost.TILES_SETTING,
- TextUtils.join(",", newTiles), ActivityManager.getCurrentUser());
+ saveTilesToSettings(newTiles);
}
public QSTile createTile(String tileSpec) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
deleted file mode 100644
index f77ff8c..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ /dev/null
@@ -1,122 +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.qs;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.media.MediaControlPanel;
-import com.android.systemui.plugins.ActivityStarter;
-
-import java.util.concurrent.Executor;
-
-/**
- * QQS mini media player
- */
-public class QuickQSMediaPlayer extends MediaControlPanel {
-
- private static final String TAG = "QQSMediaPlayer";
-
- // Button IDs for QS controls
- private static final int[] QQS_ACTION_IDS = {R.id.action0, R.id.action1, R.id.action2};
-
- /**
- * Initialize mini media player for QQS
- * @param context
- * @param parent
- * @param foregroundExecutor
- * @param backgroundExecutor
- * @param activityStarter
- */
- public QuickQSMediaPlayer(Context context, ViewGroup parent, Executor foregroundExecutor,
- Executor backgroundExecutor, ActivityStarter activityStarter) {
- super(context, parent, null, R.layout.qqs_media_panel, QQS_ACTION_IDS,
- foregroundExecutor, backgroundExecutor, activityStarter);
- }
-
- /**
- * Update media panel view for the given media session
- * @param token token for this media session
- * @param icon app notification icon
- * @param largeIcon notification's largeIcon, used as a fallback for album art
- * @param iconColor foreground color (for text, icons)
- * @param bgColor background color
- * @param actionsContainer a LinearLayout containing the media action buttons
- * @param actionsToShow indices of which actions to display in the mini player
- * (max 3: Notification.MediaStyle.MAX_MEDIA_BUTTONS_IN_COMPACT)
- * @param contentIntent Intent to send when user taps on the view
- * @param key original notification's key
- */
- public void setMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
- int iconColor, int bgColor, View actionsContainer, int[] actionsToShow,
- PendingIntent contentIntent, String key) {
- // Only update if this is a different session and currently playing
- String oldPackage = "";
- if (getController() != null) {
- oldPackage = getController().getPackageName();
- }
- MediaController controller = new MediaController(getContext(), token);
- MediaSession.Token currentToken = getMediaSessionToken();
- boolean samePlayer = currentToken != null
- && currentToken.equals(token)
- && oldPackage.equals(controller.getPackageName());
- if (getController() != null && !samePlayer && !isPlaying(controller)) {
- return;
- }
-
- super.setMediaSession(token, icon, largeIcon, iconColor, bgColor, contentIntent, null, key);
-
- LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
- int i = 0;
- if (actionsToShow != null) {
- int maxButtons = Math.min(actionsToShow.length, parentActionsLayout.getChildCount());
- maxButtons = Math.min(maxButtons, QQS_ACTION_IDS.length);
- for (; i < maxButtons; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(QQS_ACTION_IDS[i]);
- int thatId = NOTIF_ACTION_IDS[actionsToShow[i]];
- ImageButton thatBtn = parentActionsLayout.findViewById(thatId);
- if (thatBtn == null || thatBtn.getDrawable() == null
- || thatBtn.getVisibility() != View.VISIBLE) {
- thisBtn.setVisibility(View.GONE);
- continue;
- }
-
- Drawable thatIcon = thatBtn.getDrawable();
- thisBtn.setImageDrawable(thatIcon.mutate());
- thisBtn.setVisibility(View.VISIBLE);
- thisBtn.setOnClickListener(v -> {
- thatBtn.performClick();
- });
- }
- }
-
- // Hide any unused buttons
- for (; i < QQS_ACTION_IDS.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(QQS_ACTION_IDS[i]);
- thisBtn.setVisibility(View.GONE);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 6683a1c..2f06c4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -18,38 +18,33 @@
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.android.internal.logging.UiEventLogger;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
@@ -67,16 +62,17 @@
private boolean mDisabledByPolicy;
private int mMaxTiles;
protected QSPanel mFullPanel;
- private QuickQSMediaPlayer mMediaPlayer;
/** Whether or not the QS media player feature is enabled. */
private boolean mUsingMediaPlayer;
/** Whether or not the QuickQSPanel currently contains a media player. */
- private boolean mHasMediaPlayer;
+ private boolean mShowHorizontalTileLayout;
private LinearLayout mHorizontalLinearLayout;
// Only used with media
- private QSTileLayout mMediaTileLayout;
+ private QSTileLayout mHorizontalTileLayout;
private QSTileLayout mRegularTileLayout;
+ private int mLastOrientation = -1;
+ private int mMediaBottomMargin;
@Inject
public QuickQSPanel(
@@ -85,16 +81,11 @@
DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher,
QSLogger qsLogger,
- @Main Executor foregroundExecutor,
- @Background DelayableExecutor backgroundExecutor,
- @Nullable LocalBluetoothManager localBluetoothManager,
- ActivityStarter activityStarter,
- NotificationEntryManager entryManager,
+ MediaHost mediaHost,
UiEventLogger uiEventLogger
) {
- super(context, attrs, dumpManager, broadcastDispatcher, qsLogger,
- foregroundExecutor, backgroundExecutor, localBluetoothManager, activityStarter,
- entryManager, uiEventLogger);
+ super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost,
+ uiEventLogger);
if (mFooter != null) {
removeView(mFooter.getView());
}
@@ -104,6 +95,8 @@
}
removeView((View) mTileLayout);
}
+ mMediaBottomMargin = getResources().getDimensionPixelSize(
+ R.dimen.quick_settings_media_extra_bottom_margin);
mUsingMediaPlayer = Utils.useQsMediaPlayer(context);
if (mUsingMediaPlayer) {
@@ -112,40 +105,95 @@
mHorizontalLinearLayout.setClipChildren(false);
mHorizontalLinearLayout.setClipToPadding(false);
- int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing);
- mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout,
- foregroundExecutor, backgroundExecutor, activityStarter);
- LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
- lp2.setMarginEnd(marginSize);
- lp2.setMarginStart(0);
- mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2);
-
- mTileLayout = new DoubleLineTileLayout(context, mUiEventLogger);
- mMediaTileLayout = mTileLayout;
+ DoubleLineTileLayout horizontalTileLayout = new DoubleLineTileLayout(context,
+ mUiEventLogger);
+ horizontalTileLayout.setPaddingRelative(
+ horizontalTileLayout.getPaddingStart(),
+ horizontalTileLayout.getPaddingTop(),
+ horizontalTileLayout.getPaddingEnd(),
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.qqs_horizonal_tile_padding_bottom));
+ mHorizontalTileLayout = horizontalTileLayout;
mRegularTileLayout = new HeaderTileLayout(context, mUiEventLogger);
- LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
- lp.setMarginEnd(0);
- lp.setMarginStart(marginSize);
- mHorizontalLinearLayout.addView((View) mTileLayout, lp);
+ LayoutParams lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
+ int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing);
+ lp.setMarginStart(0);
+ lp.setMarginEnd(marginSize);
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ mHorizontalLinearLayout.addView((View) mHorizontalTileLayout, lp);
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+ boolean useHorizontal = shouldUseHorizontalTileLayout();
+ mTileLayout = useHorizontal ? mHorizontalTileLayout : mRegularTileLayout;
mTileLayout.setListening(mListening);
addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */);
- ((View) mRegularTileLayout).setVisibility(View.GONE);
+ ((View) mRegularTileLayout).setVisibility(!useHorizontal ? View.VISIBLE : View.GONE);
+ mHorizontalLinearLayout.setVisibility(useHorizontal ? View.VISIBLE : View.GONE);
addView((View) mRegularTileLayout, 0);
super.setPadding(0, 0, 0, 0);
+ applySideMargins(mHorizontalLinearLayout);
+ applyBottomMargin((View) mRegularTileLayout);
} else {
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
mTileLayout = new HeaderTileLayout(context, mUiEventLogger);
mTileLayout.setListening(mListening);
addView((View) mTileLayout, 0 /* Between brightness and footer */);
super.setPadding(0, 0, 0, 0);
+ applyBottomMargin((View) mTileLayout);
}
}
- public QuickQSMediaPlayer getMediaPlayer() {
- return mMediaPlayer;
+ private void applyBottomMargin(View view) {
+ int margin = getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_bottom);
+ MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
+ layoutParams.bottomMargin = margin;
+ view.setLayoutParams(layoutParams);
+ }
+
+ private void applySideMargins(View view) {
+ int margin = getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_horizontal);
+ MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
+ layoutParams.setMarginStart(margin);
+ layoutParams.setMarginEnd(margin);
+ view.setLayoutParams(layoutParams);
+ }
+
+ private void reAttachMediaHost() {
+ if (mMediaHost == null) {
+ return;
+ }
+ boolean horizontal = shouldUseHorizontalTileLayout();
+ ViewGroup host = mMediaHost.getHostView();
+ ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
+ ViewGroup currentParent = (ViewGroup) host.getParent();
+ if (currentParent != newParent) {
+ if (currentParent != null) {
+ currentParent.removeView(host);
+ }
+ newParent.addView(host);
+ LinearLayout.LayoutParams layoutParams = (LayoutParams) host.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.weight = horizontal ? 1.5f : 0;
+ layoutParams.bottomMargin = mMediaBottomMargin;
+ int marginStart = horizontal
+ ? getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_horizontal)
+ : 0;
+ layoutParams.setMarginStart(marginStart);
+ }
+ }
+
+ @Override
+ protected void addMediaHostView() {
+ mMediaHost.setVisibleChangedListener((visible) -> {
+ switchTileLayout();
+ return null;
+ });
+ mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
+ mMediaHost.setExpansion(0.0f);
+ mMediaHost.setShowsOnlyActiveMedia(true);
+ reAttachMediaHost();
}
@Override
@@ -179,6 +227,11 @@
}
@Override
+ protected boolean shouldShowDetail() {
+ return !mExpanded;
+ }
+
+ @Override
protected void drawTile(TileRecord r, State state) {
if (state instanceof SignalState) {
SignalState copy = new SignalState();
@@ -191,10 +244,19 @@
super.drawTile(r, state);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (newConfig.orientation != mLastOrientation) {
+ mLastOrientation = newConfig.orientation;
+ switchTileLayout();
+ }
+ }
+
boolean switchTileLayout() {
if (!mUsingMediaPlayer) return false;
- mHasMediaPlayer = mMediaPlayer.hasMediaSession();
- if (mHasMediaPlayer && mHorizontalLinearLayout.getVisibility() == View.GONE) {
+ mShowHorizontalTileLayout = shouldUseHorizontalTileLayout();
+ if (mShowHorizontalTileLayout && mHorizontalLinearLayout.getVisibility() == View.GONE) {
mHorizontalLinearLayout.setVisibility(View.VISIBLE);
((View) mRegularTileLayout).setVisibility(View.GONE);
mTileLayout.setListening(false);
@@ -202,11 +264,13 @@
mTileLayout.removeTile(record);
record.tile.removeCallback(record.callback);
}
- mTileLayout = mMediaTileLayout;
+ mTileLayout = mHorizontalTileLayout;
if (mHost != null) setTiles(mHost.getTiles());
mTileLayout.setListening(mListening);
+ reAttachMediaHost();
return true;
- } else if (!mHasMediaPlayer && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
+ } else if (!mShowHorizontalTileLayout
+ && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
mHorizontalLinearLayout.setVisibility(View.GONE);
((View) mRegularTileLayout).setVisibility(View.VISIBLE);
mTileLayout.setListening(false);
@@ -217,14 +281,21 @@
mTileLayout = mRegularTileLayout;
if (mHost != null) setTiles(mHost.getTiles());
mTileLayout.setListening(mListening);
+ reAttachMediaHost();
return true;
}
return false;
}
- /** Returns true if this panel currently contains a media player. */
- public boolean hasMediaPlayer() {
- return mHasMediaPlayer;
+ private boolean shouldUseHorizontalTileLayout() {
+ return mMediaHost.getVisible()
+ && getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE;
+ }
+
+ /** Returns true if this panel currently uses a horizontal tile layout. */
+ public boolean usesHorizontalLayout() {
+ return mShowHorizontalTileLayout;
}
@Override
@@ -341,7 +412,7 @@
setClipChildren(false);
setClipToPadding(false);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT);
+ LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
setLayoutParams(lp);
}
@@ -354,6 +425,7 @@
@Override
public void onFinishInflate(){
+ super.onFinishInflate();
updateResources();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index b15c6a3..3b2bea8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -220,6 +220,10 @@
mNextAlarmTextView.setSelected(true);
}
+ public QuickQSPanel getHeaderQsPanel() {
+ return mHeaderQsPanel;
+ }
+
private List<String> getIgnoredIconSlots() {
ArrayList<String> ignored = new ArrayList<>();
ignored.add(mContext.getResources().getString(
@@ -336,23 +340,6 @@
com.android.internal.R.dimen.quick_qs_offset_height);
mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-
- if (mQsDisabled) {
- lp.height = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.quick_qs_offset_height);
- } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayer()) {
- lp.height = Math.max(getMinimumHeight(),
- resources.getDimensionPixelSize(
- com.android.internal.R.dimen.quick_qs_total_height_with_media));
- } else {
- lp.height = Math.max(getMinimumHeight(),
- resources.getDimensionPixelSize(
- com.android.internal.R.dimen.quick_qs_total_height));
- }
-
- setLayoutParams(lp);
-
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 8feee10..9e2bb98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -18,8 +18,10 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
@@ -34,7 +36,6 @@
import android.util.Log;
import android.util.PathParser;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -42,7 +43,6 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Switch;
-import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -64,9 +64,10 @@
private boolean mTileState;
private boolean mCollapsedView;
private boolean mShowRippleEffect = true;
+ private float mStrokeWidthActive;
+ private float mStrokeWidthInactive;
private final ImageView mBg;
- private final TextView mDetailText;
private final int mColorActive;
private final int mColorInactive;
private final int mColorDisabled;
@@ -83,6 +84,10 @@
// Default to Quick Tile padding, and QSTileView will specify its own padding.
int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
mIconFrame = new FrameLayout(context);
+ mStrokeWidthActive = context.getResources()
+ .getDimension(com.android.internal.R.dimen.config_qsTileStrokeWidthActive);
+ mStrokeWidthInactive = context.getResources()
+ .getDimension(com.android.internal.R.dimen.config_qsTileStrokeWidthInactive);
int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
addView(mIconFrame, new LayoutParams(size, size));
mBg = new ImageView(getContext());
@@ -104,12 +109,6 @@
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.CENTER);
mIconFrame.addView(mIcon, params);
-
- // "..." afforadance below icon
- mDetailText = (TextView) LayoutInflater.from(context).inflate(R.layout.qs_tile_detail_text,
- mIconFrame, false);
- mIconFrame.addView(mDetailText);
-
mIconFrame.setClipChildren(false);
mIconFrame.setClipToPadding(false);
@@ -165,10 +164,6 @@
tile.longClick();
return true;
});
-
- if (tile.supportsDetailView()) {
- mDetailText.setVisibility(View.VISIBLE);
- }
}
public void init(OnClickListener click, OnClickListener secondaryClick,
@@ -206,7 +201,31 @@
mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
}
+ private void updateStrokeShapeWidth(QSTile.State state) {
+ Resources resources = getContext().getResources();
+ if (!(mBg.getDrawable() instanceof ShapeDrawable)) {
+ return;
+ }
+ ShapeDrawable d = (ShapeDrawable) mBg.getDrawable();
+ d.getPaint().setStyle(Paint.Style.FILL);
+ switch (state.state) {
+ case Tile.STATE_INACTIVE:
+ if (mStrokeWidthInactive >= 0) {
+ d.getPaint().setStyle(Paint.Style.STROKE);
+ d.getPaint().setStrokeWidth(mStrokeWidthInactive);
+ }
+ break;
+ case Tile.STATE_ACTIVE:
+ if (mStrokeWidthActive >= 0) {
+ d.getPaint().setStyle(Paint.Style.STROKE);
+ d.getPaint().setStrokeWidth(mStrokeWidthActive);
+ }
+ break;
+ }
+ }
+
protected void handleStateChanged(QSTile.State state) {
+ updateStrokeShapeWidth(state);
int circleColor = getCircleColor(state.state);
boolean allowAnimations = animationsEnabled();
if (circleColor != mCircleColor) {
@@ -222,8 +241,6 @@
mCircleColor = circleColor;
}
- mDetailText.setTextColor(QSTileImpl.getColorForState(getContext(), state.state));
-
mShowRippleEffect = state.showRippleEffect;
setClickable(state.state != Tile.STATE_UNAVAILABLE);
setLongClickable(state.handlesLongClick);
@@ -368,4 +385,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 7e5f2e19..87faacc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -68,8 +68,6 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QuickStatusBarHeader;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tiles.QSSettingsControllerKt;
-import com.android.systemui.qs.tiles.QSSettingsPanel;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -152,19 +150,12 @@
*/
abstract public int getMetricsCategory();
- /**
- * Experimental option on whether to use settings panels. Only loaded on creation, so the tile
- * needs to be removed and added for this to take effect.
- */
- protected final QSSettingsPanel mQSSettingsPanelOption;
-
protected QSTileImpl(QSHost host) {
mHost = host;
mContext = host.getContext();
mInstanceId = host.getNewInstanceId();
mState = newTileState();
mTmpState = newTileState();
- mQSSettingsPanelOption = QSSettingsControllerKt.getQSSettingsPanelOption();
mQSLogger = host.getQSLogger();
mUiEventLogger = host.getUiEventLogger();
}
@@ -366,10 +357,6 @@
* {@link QSTileImpl#getLongClickIntent}
*/
protected void handleLongClick() {
- if (mQSSettingsPanelOption == QSSettingsPanel.USE_DETAIL) {
- showDetail(true);
- return;
- }
Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
getLongClickIntent(), 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QSSettingsController.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/QSSettingsController.kt
deleted file mode 100644
index c7ef0be..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QSSettingsController.kt
+++ /dev/null
@@ -1,36 +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.qs.tiles
-
-import android.provider.DeviceConfig
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
-
-enum class QSSettingsPanel {
- DEFAULT,
- OPEN_LONG_PRESS,
- OPEN_CLICK,
- USE_DETAIL
-}
-
-fun getQSSettingsPanelOption(): QSSettingsPanel =
- when (DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.QS_USE_SETTINGS_PANELS, 0)) {
- 1 -> QSSettingsPanel.OPEN_LONG_PRESS
- 2 -> QSSettingsPanel.OPEN_CLICK
- 3 -> QSSettingsPanel.USE_DETAIL
- else -> QSSettingsPanel.DEFAULT
- }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index da78903..d7dd6f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -79,19 +79,15 @@
state.value = isRecording || isStarting;
state.state = (isRecording || isStarting) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_screen_record_label);
+ state.icon = ResourceIcon.get(R.drawable.ic_screenrecord);
if (isRecording) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_screenrecord);
state.secondaryLabel = mContext.getString(R.string.quick_settings_screen_record_stop);
} else if (isStarting) {
// round, since the timer isn't exact
int countdown = (int) Math.floorDiv(mMillisUntilFinished + 500, 1000);
- // TODO update icon
- state.icon = ResourceIcon.get(R.drawable.ic_qs_screenrecord);
state.secondaryLabel = String.format("%d...", countdown);
} else {
- // TODO update icon
- state.icon = ResourceIcon.get(R.drawable.ic_qs_screenrecord);
state.secondaryLabel = mContext.getString(R.string.quick_settings_screen_record_start);
}
state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 6249f82..aa63b40 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -106,6 +106,7 @@
}
public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
mName.setEnabled(enabled);
mAvatar.setEnabled(enabled);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index f169501..1279d42 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -56,7 +56,6 @@
/** Quick settings tile: Wifi **/
public class WifiTile extends QSTileImpl<SignalState> {
private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
- private static final Intent WIFI_PANEL = new Intent(Settings.Panel.ACTION_WIFI);
protected final NetworkController mController;
private final AccessPointController mWifiController;
@@ -109,21 +108,11 @@
@Override
public Intent getLongClickIntent() {
- if (mQSSettingsPanelOption == QSSettingsPanel.OPEN_LONG_PRESS) return WIFI_PANEL;
- else return WIFI_SETTINGS;
- }
-
- @Override
- public boolean supportsDetailView() {
- return getDetailAdapter() != null && mQSSettingsPanelOption == QSSettingsPanel.OPEN_CLICK;
+ return WIFI_SETTINGS;
}
@Override
protected void handleClick() {
- if (mQSSettingsPanelOption == QSSettingsPanel.OPEN_CLICK) {
- mActivityStarter.postStartActivityDismissingKeyguard(WIFI_PANEL, 0);
- return;
- }
// Secondary clicks are header clicks, just toggle.
mState.copyTo(mStateBeforeClick);
boolean wifiEnabled = mState.value;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index ae0a1c4..b253635 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -137,7 +137,7 @@
* Check if the recording is ongoing
* @return
*/
- public boolean isRecording() {
+ public synchronized boolean isRecording() {
return mIsRecording;
}
@@ -157,7 +157,7 @@
* Update the current status
* @param isRecording
*/
- public void updateState(boolean isRecording) {
+ public synchronized void updateState(boolean isRecording) {
mIsRecording = isRecording;
for (RecordingStateChangeCallback cb : mListeners) {
if (isRecording) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 390ac09..960c501 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -22,41 +22,27 @@
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
-import android.media.projection.IMediaProjection;
-import android.media.projection.IMediaProjectionManager;
-import android.media.projection.MediaProjection;
-import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.MediaStore;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
-import android.view.Surface;
-import android.view.WindowManager;
import android.widget.Toast;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.LongRunning;
-import java.io.File;
import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -66,13 +52,15 @@
public class RecordingService extends Service implements MediaRecorder.OnInfoListener {
public static final int REQUEST_CODE = 2;
- private static final int NOTIFICATION_ID = 1;
+ private static final int NOTIFICATION_RECORDING_ID = 4274;
+ private static final int NOTIFICATION_PROCESSING_ID = 4275;
+ private static final int NOTIFICATION_VIEW_ID = 4273;
private static final String TAG = "RecordingService";
private static final String CHANNEL_ID = "screen_record";
private static final String EXTRA_RESULT_CODE = "extra_resultCode";
private static final String EXTRA_DATA = "extra_data";
private static final String EXTRA_PATH = "extra_path";
- private static final String EXTRA_USE_AUDIO = "extra_useAudio";
+ private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
private static final String ACTION_START = "com.android.systemui.screenrecord.START";
@@ -80,29 +68,19 @@
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
- private static final int TOTAL_NUM_TRACKS = 1;
- private static final int VIDEO_BIT_RATE = 10000000;
- private static final int VIDEO_FRAME_RATE = 30;
- private static final int AUDIO_BIT_RATE = 16;
- private static final int AUDIO_SAMPLE_RATE = 44100;
- private static final int MAX_DURATION_MS = 60 * 60 * 1000;
- private static final long MAX_FILESIZE_BYTES = 5000000000L;
-
private final RecordingController mController;
- private MediaProjection mMediaProjection;
- private Surface mInputSurface;
- private VirtualDisplay mVirtualDisplay;
- private MediaRecorder mMediaRecorder;
private Notification.Builder mRecordingNotificationBuilder;
- private boolean mUseAudio;
+ private ScreenRecordingAudioSource mAudioSource;
private boolean mShowTaps;
private boolean mOriginalShowTaps;
- private File mTempFile;
+ private ScreenMediaRecorder mRecorder;
+ private final Executor mLongExecutor;
@Inject
- public RecordingService(RecordingController controller) {
+ public RecordingService(RecordingController controller, @LongRunning Executor executor) {
mController = controller;
+ mLongExecutor = executor;
}
/**
@@ -113,16 +91,16 @@
* android.content.Intent)}
* @param data The data from {@link android.app.Activity#onActivityResult(int, int,
* android.content.Intent)}
- * @param useAudio True to enable microphone input while recording
+ * @param audioSource The ordinal value of the audio source
+ * {@link com.android.systemui.screenrecord.ScreenRecordingAudioSource}
* @param showTaps True to make touches visible while recording
*/
- public static Intent getStartIntent(Context context, int resultCode, Intent data,
- boolean useAudio, boolean showTaps) {
+ public static Intent getStartIntent(Context context, int resultCode,
+ int audioSource, boolean showTaps) {
return new Intent(context, RecordingService.class)
.setAction(ACTION_START)
.putExtra(EXTRA_RESULT_CODE, resultCode)
- .putExtra(EXTRA_DATA, data)
- .putExtra(EXTRA_USE_AUDIO, useAudio)
+ .putExtra(EXTRA_AUDIO_SOURCE, audioSource)
.putExtra(EXTRA_SHOW_TAPS, showTaps);
}
@@ -139,36 +117,31 @@
switch (action) {
case ACTION_START:
- mUseAudio = intent.getBooleanExtra(EXTRA_USE_AUDIO, false);
+ mAudioSource = ScreenRecordingAudioSource
+ .values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)];
+ Log.d(TAG, "recording with audio source" + mAudioSource);
mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
- try {
- IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
- IMediaProjectionManager mediaService =
- IMediaProjectionManager.Stub.asInterface(b);
- IMediaProjection proj = mediaService.createProjection(getUserId(),
- getPackageName(),
- MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
- IBinder projection = proj.asBinder();
- if (projection == null) {
- Log.e(TAG, "Projection was null");
- Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG)
- .show();
- return Service.START_NOT_STICKY;
- }
- mMediaProjection = new MediaProjection(getApplicationContext(),
- IMediaProjection.Stub.asInterface(projection));
- startRecording();
- } catch (RemoteException e) {
- e.printStackTrace();
- Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG)
- .show();
- return Service.START_NOT_STICKY;
- }
+
+ mOriginalShowTaps = Settings.System.getInt(
+ getApplicationContext().getContentResolver(),
+ Settings.System.SHOW_TOUCHES, 0) != 0;
+
+ setTapsVisible(mShowTaps);
+
+ mRecorder = new ScreenMediaRecorder(
+ getApplicationContext(),
+ getUserId(),
+ mAudioSource,
+ this
+ );
+ startRecording();
break;
case ACTION_STOP:
stopRecording();
+ notificationManager.cancel(NOTIFICATION_RECORDING_ID);
saveRecording(notificationManager);
+ stopSelf();
break;
case ACTION_SHARE:
@@ -183,10 +156,10 @@
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
// Remove notification
- notificationManager.cancel(NOTIFICATION_ID);
+ notificationManager.cancel(NOTIFICATION_VIEW_ID);
startActivity(Intent.createChooser(shareIntent, shareLabel)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
break;
case ACTION_DELETE:
// Close quick shade
@@ -202,7 +175,7 @@
Toast.LENGTH_LONG).show();
// Remove notification
- notificationManager.cancel(NOTIFICATION_ID);
+ notificationManager.cancel(NOTIFICATION_VIEW_ID);
Log.d(TAG, "Deleted recording " + uri);
break;
}
@@ -224,70 +197,15 @@
*/
private void startRecording() {
try {
- File cacheDir = getCacheDir();
- cacheDir.mkdirs();
- mTempFile = File.createTempFile("temp", ".mp4", cacheDir);
- Log.d(TAG, "Writing video output to: " + mTempFile.getAbsolutePath());
-
- mOriginalShowTaps = 1 == Settings.System.getInt(
- getApplicationContext().getContentResolver(),
- Settings.System.SHOW_TOUCHES, 0);
- setTapsVisible(mShowTaps);
-
- // Set up media recorder
- mMediaRecorder = new MediaRecorder();
- if (mUseAudio) {
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- }
- mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
-
- // Set up video
- DisplayMetrics metrics = new DisplayMetrics();
- WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getRealMetrics(metrics);
- int screenWidth = metrics.widthPixels;
- int screenHeight = metrics.heightPixels;
- mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
- mMediaRecorder.setVideoSize(screenWidth, screenHeight);
- mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
- mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
- mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
- mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
-
- // Set up audio
- if (mUseAudio) {
- mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
- mMediaRecorder.setAudioChannels(TOTAL_NUM_TRACKS);
- mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
- mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
- }
-
- mMediaRecorder.setOutputFile(mTempFile);
- mMediaRecorder.prepare();
-
- // Create surface
- mInputSurface = mMediaRecorder.getSurface();
- mVirtualDisplay = mMediaProjection.createVirtualDisplay(
- "Recording Display",
- screenWidth,
- screenHeight,
- metrics.densityDpi,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
- mInputSurface,
- null,
- null);
-
- mMediaRecorder.setOnInfoListener(this);
- mMediaRecorder.start();
+ mRecorder.start();
mController.updateState(true);
- } catch (IOException e) {
- Log.e(TAG, "Error starting screen recording: " + e.getMessage());
+ createRecordingNotification();
+ } catch (IOException | RemoteException e) {
+ Toast.makeText(this,
+ R.string.screenrecord_start_error, Toast.LENGTH_LONG)
+ .show();
e.printStackTrace();
- throw new RuntimeException(e);
}
-
- createRecordingNotification();
}
private void createRecordingNotification() {
@@ -306,7 +224,7 @@
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_name));
- String notificationTitle = mUseAudio
+ String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
: res.getString(R.string.screenrecord_ongoing_screen_only);
@@ -323,9 +241,10 @@
this, REQUEST_CODE, getStopIntent(this),
PendingIntent.FLAG_UPDATE_CURRENT))
.addExtras(extras);
- notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build());
+ notificationManager.notify(NOTIFICATION_RECORDING_ID,
+ mRecordingNotificationBuilder.build());
Notification notification = mRecordingNotificationBuilder.build();
- startForeground(NOTIFICATION_ID, notification);
+ startForeground(NOTIFICATION_RECORDING_ID, notification);
}
private Notification createSaveNotification(Uri uri) {
@@ -392,47 +311,38 @@
private void stopRecording() {
setTapsVisible(mOriginalShowTaps);
- mMediaRecorder.stop();
- mMediaRecorder.release();
- mMediaRecorder = null;
- mMediaProjection.stop();
- mMediaProjection = null;
- mInputSurface.release();
- mVirtualDisplay.release();
- stopSelf();
+ mRecorder.end();
mController.updateState(false);
}
private void saveRecording(NotificationManager notificationManager) {
- String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
- .format(new Date());
+ Resources res = getApplicationContext().getResources();
+ String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
+ ? res.getString(R.string.screenrecord_ongoing_screen_only)
+ : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+ Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
+ .setContentTitle(notificationTitle)
+ .setContentText(
+ getResources().getString(R.string.screenrecord_background_processing_label))
+ .setSmallIcon(R.drawable.ic_screenrecord);
+ notificationManager.notify(NOTIFICATION_PROCESSING_ID, builder.build());
- ContentValues values = new ContentValues();
- values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
- values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
- values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
- values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
-
- ContentResolver resolver = getContentResolver();
- Uri collectionUri = MediaStore.Video.Media.getContentUri(
- MediaStore.VOLUME_EXTERNAL_PRIMARY);
- Uri itemUri = resolver.insert(collectionUri, values);
-
- try {
- // Add to the mediastore
- OutputStream os = resolver.openOutputStream(itemUri, "w");
- Files.copy(mTempFile.toPath(), os);
- os.close();
-
- Notification notification = createSaveNotification(itemUri);
- notificationManager.notify(NOTIFICATION_ID, notification);
-
- mTempFile.delete();
- } catch (IOException e) {
- Log.e(TAG, "Error saving screen recording: " + e.getMessage());
- Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
- .show();
- }
+ mLongExecutor.execute(() -> {
+ try {
+ Log.d(TAG, "saving recording");
+ Notification notification = createSaveNotification(mRecorder.save());
+ if (!mController.isRecording()) {
+ Log.d(TAG, "showing saved notification");
+ notificationManager.notify(NOTIFICATION_VIEW_ID, notification);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error saving screen recording: " + e.getMessage());
+ Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
+ .show();
+ } finally {
+ notificationManager.cancel(NOTIFICATION_PROCESSING_ID);
+ }
+ });
}
private void setTapsVisible(boolean turnOn) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
new file mode 100644
index 0000000..752f4fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -0,0 +1,290 @@
+/*
+ * 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.screenrecord;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioFormat;
+import android.media.AudioPlaybackCaptureConfiguration;
+import android.media.AudioRecord;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.media.MediaRecorder;
+import android.media.projection.MediaProjection;
+import android.util.Log;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Recording internal audio
+ */
+public class ScreenInternalAudioRecorder {
+ private static String TAG = "ScreenAudioRecorder";
+ private static final int TIMEOUT = 500;
+ private final Context mContext;
+ private AudioRecord mAudioRecord;
+ private AudioRecord mAudioRecordMic;
+ private Config mConfig = new Config();
+ private Thread mThread;
+ private MediaProjection mMediaProjection;
+ private MediaCodec mCodec;
+ private long mPresentationTime;
+ private long mTotalBytes;
+ private MediaMuxer mMuxer;
+ private String mOutFile;
+ private boolean mMic;
+
+ private int mTrackId = -1;
+
+ public ScreenInternalAudioRecorder(String outFile, Context context,
+ MediaProjection mp, boolean includeMicInput) throws IOException {
+ mMic = includeMicInput;
+ mOutFile = outFile;
+ mMuxer = new MediaMuxer(outFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ mContext = context;
+ mMediaProjection = mp;
+ Log.d(TAG, "creating audio file " + outFile);
+ setupSimple();
+ }
+ /**
+ * Audio recoding configuration
+ */
+ public static class Config {
+ public int channelOutMask = AudioFormat.CHANNEL_OUT_MONO;
+ public int channelInMask = AudioFormat.CHANNEL_IN_MONO;
+ public int encoding = AudioFormat.ENCODING_PCM_16BIT;
+ public int sampleRate = 44100;
+ public int bitRate = 196000;
+ public int bufferSizeBytes = 1 << 17;
+ public boolean privileged = true;
+ public boolean legacy_app_looback = false;
+
+ @Override
+ public String toString() {
+ return "channelMask=" + channelOutMask
+ + "\n encoding=" + encoding
+ + "\n sampleRate=" + sampleRate
+ + "\n bufferSize=" + bufferSizeBytes
+ + "\n privileged=" + privileged
+ + "\n legacy app looback=" + legacy_app_looback;
+ }
+
+ }
+
+ private void setupSimple() throws IOException {
+ int size = AudioRecord.getMinBufferSize(
+ mConfig.sampleRate, mConfig.channelInMask,
+ mConfig.encoding) * 2;
+
+ Log.d(TAG, "audio buffer size: " + size);
+
+ AudioFormat format = new AudioFormat.Builder()
+ .setEncoding(mConfig.encoding)
+ .setSampleRate(mConfig.sampleRate)
+ .setChannelMask(mConfig.channelOutMask)
+ .build();
+
+ AudioPlaybackCaptureConfiguration playbackConfig =
+ new AudioPlaybackCaptureConfiguration.Builder(mMediaProjection)
+ .addMatchingUsage(AudioAttributes.USAGE_MEDIA)
+ .addMatchingUsage(AudioAttributes.USAGE_UNKNOWN)
+ .addMatchingUsage(AudioAttributes.USAGE_GAME)
+ .build();
+
+ mAudioRecord = new AudioRecord.Builder()
+ .setAudioFormat(format)
+ .setAudioPlaybackCaptureConfig(playbackConfig)
+ .build();
+
+ if (mMic) {
+ mAudioRecordMic = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
+ mConfig.sampleRate, AudioFormat.CHANNEL_IN_MONO, mConfig.encoding, size);
+ }
+
+ mCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
+ MediaFormat medFormat = MediaFormat.createAudioFormat(
+ MediaFormat.MIMETYPE_AUDIO_AAC, mConfig.sampleRate, 1);
+ medFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,
+ MediaCodecInfo.CodecProfileLevel.AACObjectLC);
+ medFormat.setInteger(MediaFormat.KEY_BIT_RATE, mConfig.bitRate);
+ medFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, mConfig.encoding);
+ mCodec.configure(medFormat,
+ null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+ mThread = new Thread(() -> {
+ short[] bufferInternal = null;
+ short[] bufferMic = null;
+ byte[] buffer = null;
+
+ if (mMic) {
+ bufferInternal = new short[size / 2];
+ bufferMic = new short[size / 2];
+ } else {
+ buffer = new byte[size];
+ }
+
+ while (true) {
+ int readBytes = 0;
+ int readShortsInternal = 0;
+ int readShortsMic = 0;
+ if (mMic) {
+ readShortsInternal = mAudioRecord.read(bufferInternal, 0,
+ bufferInternal.length);
+ readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+ readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
+ buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
+ readShortsMic);
+ } else {
+ readBytes = mAudioRecord.read(buffer, 0, buffer.length);
+ }
+
+ //exit the loop when at end of stream
+ if (readBytes < 0) {
+ Log.e(TAG, "read error " + readBytes +
+ ", shorts internal: " + readShortsInternal +
+ ", shorts mic: " + readShortsMic);
+ break;
+ }
+ encode(buffer, readBytes);
+ }
+ endStream();
+ });
+ }
+
+ private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
+ int size = Math.max(a1Limit, a2Limit);
+ if (size < 0) return new byte[0];
+ byte[] buff = new byte[size * 2];
+ for (int i = 0; i < size; i++) {
+ int sum;
+ if (i > a1Limit) {
+ sum = a2[i];
+ } else if (i > a2Limit) {
+ sum = a1[i];
+ } else {
+ sum = (int) a1[i] + (int) a2[i];
+ }
+
+ if (sum > Short.MAX_VALUE) sum = Short.MAX_VALUE;
+ if (sum < Short.MIN_VALUE) sum = Short.MIN_VALUE;
+ int byteIndex = i * 2;
+ buff[byteIndex] = (byte) (sum & 0xff);
+ buff[byteIndex + 1] = (byte) ((sum >> 8) & 0xff);
+ }
+ return buff;
+ }
+
+ private void encode(byte[] buffer, int readBytes) {
+ int offset = 0;
+ while (readBytes > 0) {
+ int totalBytesRead = 0;
+ int bufferIndex = mCodec.dequeueInputBuffer(TIMEOUT);
+ if (bufferIndex < 0) {
+ writeOutput();
+ return;
+ }
+ ByteBuffer buff = mCodec.getInputBuffer(bufferIndex);
+ buff.clear();
+ int bufferSize = buff.capacity();
+ int bytesToRead = readBytes > bufferSize ? bufferSize : readBytes;
+ totalBytesRead += bytesToRead;
+ readBytes -= bytesToRead;
+ buff.put(buffer, offset, bytesToRead);
+ offset += bytesToRead;
+ mCodec.queueInputBuffer(bufferIndex, 0, bytesToRead, mPresentationTime, 0);
+ mTotalBytes += totalBytesRead;
+ mPresentationTime = 1000000L * (mTotalBytes / 2) / mConfig.sampleRate;
+
+ writeOutput();
+ }
+ }
+
+ private void endStream() {
+ int bufferIndex = mCodec.dequeueInputBuffer(TIMEOUT);
+ mCodec.queueInputBuffer(bufferIndex, 0, 0, mPresentationTime,
+ MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ writeOutput();
+ }
+
+ private void writeOutput() {
+ while (true) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ int bufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT);
+ if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mTrackId = mMuxer.addTrack(mCodec.getOutputFormat());
+ mMuxer.start();
+ continue;
+ }
+ if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ break;
+ }
+ if (mTrackId < 0) return;
+ ByteBuffer buff = mCodec.getOutputBuffer(bufferIndex);
+
+ if (!((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0
+ && bufferInfo.size != 0)) {
+ mMuxer.writeSampleData(mTrackId, buff, bufferInfo);
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, false);
+ }
+ }
+
+ /**
+ * start recording
+ */
+ public void start() {
+ if (mThread != null) {
+ Log.e(TAG, "a recording is being done in parallel or stop is not called");
+ }
+ mAudioRecord.startRecording();
+ if (mMic) mAudioRecordMic.startRecording();
+ Log.d(TAG, "channel count " + mAudioRecord.getChannelCount());
+ mCodec.start();
+ if (mAudioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
+ Log.e(TAG, "Error starting audio recording");
+ return;
+ }
+ mThread.start();
+ }
+
+ /**
+ * end recording
+ */
+ public void end() {
+ mAudioRecord.stop();
+ if (mMic) {
+ mAudioRecordMic.stop();
+ }
+ mAudioRecord.release();
+ if (mMic) {
+ mAudioRecordMic.release();
+ }
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mCodec.stop();
+ mCodec.release();
+ mMuxer.stop();
+ mMuxer.release();
+ mThread = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
new file mode 100644
index 0000000..c967648
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -0,0 +1,248 @@
+/*
+ * 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.screenrecord;
+
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.MediaMuxer;
+import android.media.MediaRecorder;
+import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjection;
+import android.media.projection.MediaProjectionManager;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.MediaStore;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Recording screen and mic/internal audio
+ */
+public class ScreenMediaRecorder {
+ private static final int TOTAL_NUM_TRACKS = 1;
+ private static final int VIDEO_BIT_RATE = 10000000;
+ private static final int VIDEO_FRAME_RATE = 30;
+ private static final int AUDIO_BIT_RATE = 16;
+ private static final int AUDIO_SAMPLE_RATE = 44100;
+ private static final int MAX_DURATION_MS = 60 * 60 * 1000;
+ private static final long MAX_FILESIZE_BYTES = 5000000000L;
+ private static final String TAG = "ScreenMediaRecorder";
+
+
+ private File mTempVideoFile;
+ private File mTempAudioFile;
+ private MediaProjection mMediaProjection;
+ private Surface mInputSurface;
+ private VirtualDisplay mVirtualDisplay;
+ private MediaRecorder mMediaRecorder;
+ private int mUser;
+ private ScreenRecordingMuxer mMuxer;
+ private ScreenInternalAudioRecorder mAudio;
+ private ScreenRecordingAudioSource mAudioSource;
+
+ private Context mContext;
+ MediaRecorder.OnInfoListener mListener;
+
+ public ScreenMediaRecorder(Context context,
+ int user, ScreenRecordingAudioSource audioSource,
+ MediaRecorder.OnInfoListener listener) {
+ mContext = context;
+ mUser = user;
+ mListener = listener;
+ mAudioSource = audioSource;
+ }
+
+ private void prepare() throws IOException, RemoteException {
+ //Setup media projection
+ IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
+ IMediaProjectionManager mediaService =
+ IMediaProjectionManager.Stub.asInterface(b);
+ IMediaProjection proj = null;
+ proj = mediaService.createProjection(mUser, mContext.getPackageName(),
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
+ IBinder projection = proj.asBinder();
+ mMediaProjection = new MediaProjection(mContext,
+ IMediaProjection.Stub.asInterface(projection));
+
+ File cacheDir = mContext.getCacheDir();
+ cacheDir.mkdirs();
+ mTempVideoFile = File.createTempFile("temp", ".mp4", cacheDir);
+
+ // Set up media recorder
+ mMediaRecorder = new MediaRecorder();
+
+ // Set up audio source
+ if (mAudioSource == MIC) {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+
+
+ // Set up video
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getRealMetrics(metrics);
+ int screenWidth = metrics.widthPixels;
+ int screenHeight = metrics.heightPixels;
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setVideoSize(screenWidth, screenHeight);
+ mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
+ mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+ mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
+ mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
+
+ // Set up audio
+ if (mAudioSource == MIC) {
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
+ mMediaRecorder.setAudioChannels(TOTAL_NUM_TRACKS);
+ mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
+ mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
+ }
+
+ mMediaRecorder.setOutputFile(mTempVideoFile);
+ mMediaRecorder.prepare();
+ // Create surface
+ mInputSurface = mMediaRecorder.getSurface();
+ mVirtualDisplay = mMediaProjection.createVirtualDisplay(
+ "Recording Display",
+ screenWidth,
+ screenHeight,
+ metrics.densityDpi,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+ mInputSurface,
+ null,
+ null);
+
+ mMediaRecorder.setOnInfoListener(mListener);
+ if (mAudioSource == INTERNAL ||
+ mAudioSource == MIC_AND_INTERNAL) {
+ mTempAudioFile = File.createTempFile("temp", ".aac",
+ mContext.getCacheDir());
+ mAudio = new ScreenInternalAudioRecorder(mTempAudioFile.getAbsolutePath(), mContext,
+ mMediaProjection, mAudioSource == MIC_AND_INTERNAL);
+ }
+
+ }
+
+ /**
+ * Start screen recording
+ */
+ void start() throws IOException, RemoteException {
+ Log.d(TAG, "start recording");
+ prepare();
+ mMediaRecorder.start();
+ recordInternalAudio();
+ }
+
+ /**
+ * End screen recording
+ */
+ void end() {
+ mMediaRecorder.stop();
+ mMediaProjection.stop();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ mMediaProjection = null;
+ mInputSurface.release();
+ mVirtualDisplay.release();
+ stopInternalAudioRecording();
+
+ Log.d(TAG, "end recording");
+ }
+
+ private void stopInternalAudioRecording() {
+ if (mAudioSource == INTERNAL || mAudioSource == MIC_AND_INTERNAL) {
+ mAudio.end();
+ mAudio = null;
+ }
+ }
+
+ private void recordInternalAudio() {
+ if (mAudioSource == INTERNAL || mAudioSource == MIC_AND_INTERNAL) {
+ mAudio.start();
+ }
+ }
+
+ /**
+ * Store recorded video
+ */
+ Uri save() throws IOException {
+ String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
+ .format(new Date());
+
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
+ values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
+ values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
+ values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
+
+ ContentResolver resolver = mContext.getContentResolver();
+ Uri collectionUri = MediaStore.Video.Media.getContentUri(
+ MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ Uri itemUri = resolver.insert(collectionUri, values);
+
+ Log.d(TAG, itemUri.toString());
+ if (mAudioSource == MIC_AND_INTERNAL || mAudioSource == INTERNAL) {
+ try {
+ Log.d(TAG, "muxing recording");
+ File file = File.createTempFile("temp", ".mp4",
+ mContext.getCacheDir());
+ mMuxer = new ScreenRecordingMuxer(MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,
+ file.getAbsolutePath(),
+ mTempVideoFile.getAbsolutePath(),
+ mTempAudioFile.getAbsolutePath());
+ mMuxer.mux();
+ mTempVideoFile.delete();
+ mTempVideoFile = file;
+ } catch (IOException e) {
+ Log.e(TAG, "muxing recording " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ // Add to the mediastore
+ OutputStream os = resolver.openOutputStream(itemUri, "w");
+ Files.copy(mTempVideoFile.toPath(), os);
+ os.close();
+ mTempVideoFile.delete();
+ if (mTempAudioFile != null) mTempAudioFile.delete();
+ return itemUri;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index 26973d0..abd7e71 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -16,17 +16,30 @@
package com.android.systemui.screenrecord;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE;
+
import android.app.Activity;
import android.app.PendingIntent;
import android.os.Bundle;
+import android.util.Log;
import android.view.Gravity;
+import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.Spinner;
import android.widget.Switch;
import com.android.systemui.R;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.inject.Inject;
/**
@@ -35,10 +48,15 @@
public class ScreenRecordDialog extends Activity {
private static final long DELAY_MS = 3000;
private static final long INTERVAL_MS = 1000;
+ private static final String TAG = "ScreenRecordDialog";
private final RecordingController mController;
- private Switch mAudioSwitch;
private Switch mTapsSwitch;
+ private Switch mAudioSwitch;
+ private Spinner mOptions;
+ private List<ScreenRecordingAudioSource> mModes;
+ private int mSelected;
+
@Inject
public ScreenRecordDialog(RecordingController controller) {
@@ -54,6 +72,7 @@
window.getDecorView();
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
window.setGravity(Gravity.TOP);
+ setTitle(R.string.screenrecord_name);
setContentView(R.layout.screen_record_dialog);
@@ -68,17 +87,32 @@
finish();
});
+ mModes = new ArrayList<>();
+ mModes.add(INTERNAL);
+ mModes.add(MIC);
+ mModes.add(MIC_AND_INTERNAL);
+
mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
mTapsSwitch = findViewById(R.id.screenrecord_taps_switch);
+ mOptions = findViewById(R.id.screen_recording_options);
+ ArrayAdapter a = new ScreenRecordingAdapter(getApplicationContext(),
+ android.R.layout.simple_spinner_dropdown_item,
+ mModes);
+ a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mOptions.setAdapter(a);
+
}
private void requestScreenCapture() {
- boolean useAudio = mAudioSwitch.isChecked();
boolean showTaps = mTapsSwitch.isChecked();
+ ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked()
+ ? (ScreenRecordingAudioSource) mOptions.getSelectedItem()
+ : NONE;
PendingIntent startIntent = PendingIntent.getForegroundService(this,
RecordingService.REQUEST_CODE,
RecordingService.getStartIntent(
- ScreenRecordDialog.this, RESULT_OK, null, useAudio, showTaps),
+ ScreenRecordDialog.this, RESULT_OK,
+ audioMode.ordinal(), showTaps),
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent stopIntent = PendingIntent.getService(this,
RecordingService.REQUEST_CODE,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
new file mode 100644
index 0000000..2e0e746
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -0,0 +1,124 @@
+/*
+ * 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.screenrecord;
+
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
+import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.List;
+
+/**
+ * Screen recording view adapter
+ */
+public class ScreenRecordingAdapter extends ArrayAdapter<ScreenRecordingAudioSource> {
+ private LinearLayout mSelectedMic;
+ private LinearLayout mSelectedInternal;
+ private LinearLayout mSelectedMicAndInternal;
+ private LinearLayout mMicOption;
+ private LinearLayout mMicAndInternalOption;
+ private LinearLayout mInternalOption;
+
+ public ScreenRecordingAdapter(Context context, int resource,
+ List<ScreenRecordingAudioSource> objects) {
+ super(context, resource, objects);
+ initViews();
+ }
+
+ private void initViews() {
+ mSelectedInternal = getSelected(R.string.screenrecord_device_audio_label);
+ mSelectedMic = getSelected(R.string.screenrecord_mic_label);
+ mSelectedMicAndInternal = getSelected(R.string.screenrecord_device_audio_and_mic_label);
+
+ mMicOption = getOption(R.string.screenrecord_mic_label, Resources.ID_NULL);
+ mMicOption.removeViewAt(1);
+
+ mMicAndInternalOption = getOption(
+ R.string.screenrecord_device_audio_and_mic_label, Resources.ID_NULL);
+ mMicAndInternalOption.removeViewAt(1);
+
+ mInternalOption = getOption(R.string.screenrecord_device_audio_label,
+ R.string.screenrecord_device_audio_description);
+ }
+
+ private LinearLayout getOption(int label, int description) {
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LinearLayout layout = (LinearLayout) inflater
+ .inflate(R.layout.screen_record_dialog_audio_source, null, false);
+ ((TextView) layout.findViewById(R.id.screen_recording_dialog_source_text))
+ .setText(label);
+ if (description != Resources.ID_NULL)
+ ((TextView) layout.findViewById(R.id.screen_recording_dialog_source_description))
+ .setText(description);
+ return layout;
+ }
+
+ private LinearLayout getSelected(int label) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ LinearLayout layout = (LinearLayout) inflater
+ .inflate(R.layout.screen_record_dialog_audio_source_selected, null, false);
+ ((TextView) layout.findViewById(R.id.screen_recording_dialog_source_text))
+ .setText(label);
+ return layout;
+ }
+
+ private void setDescription(LinearLayout layout, int description) {
+ if (description != Resources.ID_NULL) {
+ ((TextView) layout.getChildAt(1)).setText(description);
+ }
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ switch (getItem(position)) {
+ case INTERNAL:
+ return mInternalOption;
+ case MIC_AND_INTERNAL:
+ return mMicAndInternalOption;
+ case MIC:
+ return mMicOption;
+ default:
+ return super.getDropDownView(position, convertView, parent);
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ switch (getItem(position)) {
+ case INTERNAL:
+ return mSelectedInternal;
+ case MIC_AND_INTERNAL:
+ return mSelectedMicAndInternal;
+ case MIC:
+ return mSelectedMic;
+ default:
+ return super.getView(position, convertView, parent);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAudioSource.java
similarity index 75%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
copy to packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAudioSource.java
index d0f7607..ee11865 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAudioSource.java
@@ -13,12 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.UserIdInt
+package com.android.systemui.screenrecord;
-data class BubbleXmlEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String
-)
+/**
+ * Audio sources
+ */
+public enum ScreenRecordingAudioSource {
+ NONE,
+ INTERNAL,
+ MIC,
+ MIC_AND_INTERNAL;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
new file mode 100644
index 0000000..7ffcfd4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
@@ -0,0 +1,104 @@
+/*
+ * 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.screenrecord;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaMuxer;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * Mixing audio and video tracks
+ */
+public class ScreenRecordingMuxer {
+ // size of a memory page for cache coherency
+ private static final int BUFFER_SIZE = 1024 * 4096;
+ private String[] mFiles;
+ private String mOutFile;
+ private int mFormat;
+ private ArrayMap<Pair<MediaExtractor, Integer>, Integer> mExtractorIndexToMuxerIndex
+ = new ArrayMap<>();
+ private ArrayList<MediaExtractor> mExtractors = new ArrayList<>();
+
+ private static String TAG = "ScreenRecordingMuxer";
+ public ScreenRecordingMuxer(@MediaMuxer.Format int format, String outfileName,
+ String... inputFileNames) {
+ mFiles = inputFileNames;
+ mOutFile = outfileName;
+ mFormat = format;
+ Log.d(TAG, "out: " + mOutFile + " , in: " + mFiles[0]);
+ }
+
+ /**
+ * RUN IN THE BACKGROUND THREAD!
+ */
+ public void mux() throws IOException {
+ MediaMuxer muxer = null;
+ muxer = new MediaMuxer(mOutFile, mFormat);
+ // Add extractors
+ for (String file: mFiles) {
+ MediaExtractor extractor = new MediaExtractor();
+ try {
+ extractor.setDataSource(file);
+ } catch (IOException e) {
+ Log.e(TAG, "error creating extractor: " + file);
+ e.printStackTrace();
+ continue;
+ }
+ Log.d(TAG, file + " track count: " + extractor.getTrackCount());
+ mExtractors.add(extractor);
+ for (int i = 0; i < extractor.getTrackCount(); i++) {
+ int muxId = muxer.addTrack(extractor.getTrackFormat(i));
+ Log.d(TAG, "created extractor format" + extractor.getTrackFormat(i).toString());
+ mExtractorIndexToMuxerIndex.put(Pair.create(extractor, i), muxId);
+ }
+ }
+
+ muxer.start();
+ for (Pair<MediaExtractor, Integer> pair: mExtractorIndexToMuxerIndex.keySet()) {
+ MediaExtractor extractor = pair.first;
+ extractor.selectTrack(pair.second);
+ int muxId = mExtractorIndexToMuxerIndex.get(pair);
+ Log.d(TAG, "track format: " + extractor.getTrackFormat(pair.second));
+ extractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ int offset;
+ while (true) {
+ offset = buffer.arrayOffset();
+ info.size = extractor.readSampleData(buffer, offset);
+ if (info.size < 0) break;
+ info.presentationTimeUs = extractor.getSampleTime();
+ info.flags = extractor.getSampleFlags();
+ muxer.writeSampleData(muxId, buffer, info);
+ extractor.advance();
+ }
+ }
+
+ for (MediaExtractor extractor: mExtractors) {
+ extractor.release();
+ }
+ muxer.stop();
+ muxer.release();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 4148289..6f68ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -16,6 +16,8 @@
package com.android.systemui.screenshot;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -54,6 +56,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
@@ -61,16 +64,19 @@
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
@@ -155,6 +161,9 @@
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip";
+ // From WizardManagerHelper.java
+ private static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
+
private static final String TAG = "GlobalScreenshot";
private static final long SCREENSHOT_FLASH_IN_DURATION_MS = 133;
@@ -169,7 +178,7 @@
private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
private static final float ROUNDED_CORNER_RADIUS = .05f;
- private static final long SCREENSHOT_CORNER_TIMEOUT_MILLIS = 6000;
+ private static final int SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS = 6000;
private static final int MESSAGE_CORNER_TIMEOUT = 2;
private final Interpolator mAccelerateInterpolator = new AccelerateInterpolator();
@@ -183,24 +192,25 @@
private final Display mDisplay;
private final DisplayMetrics mDisplayMetrics;
- private final View mScreenshotLayout;
- private final ScreenshotSelectorView mScreenshotSelectorView;
- private final ImageView mScreenshotAnimatedView;
- private final ImageView mScreenshotPreview;
- private final ImageView mScreenshotFlash;
- private final ImageView mActionsContainerBackground;
- private final FrameLayout mActionsContainer;
- private final LinearLayout mActionsView;
- private final ImageView mBackgroundProtection;
- private final FrameLayout mDismissButton;
- private final ImageView mDismissImage;
+ private View mScreenshotLayout;
+ private ScreenshotSelectorView mScreenshotSelectorView;
+ private ImageView mScreenshotAnimatedView;
+ private ImageView mScreenshotPreview;
+ private ImageView mScreenshotFlash;
+ private ImageView mActionsContainerBackground;
+ private HorizontalScrollView mActionsContainer;
+ private LinearLayout mActionsView;
+ private ImageView mBackgroundProtection;
+ private FrameLayout mDismissButton;
private Bitmap mScreenBitmap;
private SaveImageInBackgroundTask mSaveInBgTask;
private Animator mScreenshotAnimation;
private Runnable mOnCompleteRunnable;
- private boolean mInDarkMode = false;
private Animator mDismissAnimation;
+ private boolean mInDarkMode = false;
+ private boolean mDirectionLTR = true;
+ private boolean mOrientationPortrait = true;
private float mScreenshotOffsetXPx;
private float mScreenshotOffsetYPx;
@@ -232,57 +242,18 @@
*/
@Inject
public GlobalScreenshot(
- Context context, @Main Resources resources, LayoutInflater layoutInflater,
+ Context context, @Main Resources resources,
ScreenshotNotificationsController screenshotNotificationsController,
UiEventLogger uiEventLogger) {
mContext = context;
mNotificationsController = screenshotNotificationsController;
mUiEventLogger = uiEventLogger;
- // Inflate the screenshot layout
- mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
- mScreenshotAnimatedView =
- mScreenshotLayout.findViewById(R.id.global_screenshot_animated_view);
- mScreenshotAnimatedView.setClipToOutline(true);
- mScreenshotAnimatedView.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
- ROUNDED_CORNER_RADIUS * view.getWidth());
- }
- });
- mScreenshotPreview = mScreenshotLayout.findViewById(R.id.global_screenshot_preview);
- mScreenshotPreview.setClipToOutline(true);
- mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
- ROUNDED_CORNER_RADIUS * view.getWidth());
- }
- });
-
- mActionsContainerBackground = mScreenshotLayout.findViewById(
- R.id.global_screenshot_actions_container_background);
- mActionsContainer = mScreenshotLayout.findViewById(
- R.id.global_screenshot_actions_container);
- mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions);
- mBackgroundProtection = mScreenshotLayout.findViewById(
- R.id.global_screenshot_actions_background);
- mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button);
- mDismissButton.setOnClickListener(view -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
- dismissScreenshot("dismiss_button", false);
- mOnCompleteRunnable.run();
- });
- mDismissImage = mDismissButton.findViewById(R.id.global_screenshot_dismiss_image);
-
- mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
- mScreenshotSelectorView = mScreenshotLayout.findViewById(R.id.global_screenshot_selector);
- mScreenshotLayout.setFocusable(true);
- mScreenshotSelectorView.setFocusable(true);
- mScreenshotSelectorView.setFocusableInTouchMode(true);
- mScreenshotAnimatedView.setPivotX(0);
- mScreenshotAnimatedView.setPivotY(0);
+ reloadAssets();
+ Configuration config = mContext.getResources().getConfiguration();
+ mInDarkMode = config.isNightModeActive();
+ mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
+ mOrientationPortrait = config.orientation == ORIENTATION_PORTRAIT;
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
@@ -333,6 +304,121 @@
inoutInfo.touchableRegion.set(touchRegion);
}
+ private void onConfigChanged(Configuration newConfig) {
+ boolean needsUpdate = false;
+ // dark mode
+ if (newConfig.isNightModeActive()) {
+ // Night mode is active, we're using dark theme
+ if (!mInDarkMode) {
+ mInDarkMode = true;
+ needsUpdate = true;
+ }
+ } else {
+ // Night mode is not active, we're using the light theme
+ if (mInDarkMode) {
+ mInDarkMode = false;
+ needsUpdate = true;
+ }
+ }
+
+ // RTL configuration
+ switch (newConfig.getLayoutDirection()) {
+ case View.LAYOUT_DIRECTION_LTR:
+ if (!mDirectionLTR) {
+ mDirectionLTR = true;
+ needsUpdate = true;
+ }
+ break;
+ case View.LAYOUT_DIRECTION_RTL:
+ if (mDirectionLTR) {
+ mDirectionLTR = false;
+ needsUpdate = true;
+ }
+ break;
+ }
+
+ // portrait/landscape orientation
+ switch (newConfig.orientation) {
+ case ORIENTATION_PORTRAIT:
+ if (!mOrientationPortrait) {
+ mOrientationPortrait = true;
+ needsUpdate = true;
+ }
+ break;
+ case ORIENTATION_LANDSCAPE:
+ if (mOrientationPortrait) {
+ mOrientationPortrait = false;
+ needsUpdate = true;
+ }
+ break;
+ }
+
+ if (needsUpdate) {
+ reloadAssets();
+ }
+ }
+
+ /**
+ * Update assets (called when the dark theme status changes). We only need to update the dismiss
+ * button and the actions container background, since the buttons are re-inflated on demand.
+ */
+ private void reloadAssets() {
+ boolean wasAttached = mScreenshotLayout != null && mScreenshotLayout.isAttachedToWindow();
+ if (wasAttached) {
+ mWindowManager.removeView(mScreenshotLayout);
+ }
+
+ // Inflate the screenshot layout
+ mScreenshotLayout = LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
+ mScreenshotAnimatedView =
+ mScreenshotLayout.findViewById(R.id.global_screenshot_animated_view);
+ mScreenshotAnimatedView.setClipToOutline(true);
+ mScreenshotAnimatedView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
+ ROUNDED_CORNER_RADIUS * view.getWidth());
+ }
+ });
+ mScreenshotPreview = mScreenshotLayout.findViewById(R.id.global_screenshot_preview);
+ mScreenshotPreview.setClipToOutline(true);
+ mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
+ ROUNDED_CORNER_RADIUS * view.getWidth());
+ }
+ });
+
+ mActionsContainerBackground = mScreenshotLayout.findViewById(
+ R.id.global_screenshot_actions_container_background);
+ mActionsContainer = mScreenshotLayout.findViewById(
+ R.id.global_screenshot_actions_container);
+ mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions);
+ mBackgroundProtection = mScreenshotLayout.findViewById(
+ R.id.global_screenshot_actions_background);
+ mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button);
+ mDismissButton.setOnClickListener(view -> {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
+ dismissScreenshot("dismiss_button", false);
+ mOnCompleteRunnable.run();
+ });
+
+ mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
+ mScreenshotSelectorView = mScreenshotLayout.findViewById(R.id.global_screenshot_selector);
+ mScreenshotLayout.setFocusable(true);
+ mScreenshotSelectorView.setFocusable(true);
+ mScreenshotSelectorView.setFocusableInTouchMode(true);
+ mScreenshotAnimatedView.setPivotX(0);
+ mScreenshotAnimatedView.setPivotY(0);
+ mActionsContainer.setScrollX(0);
+
+ if (wasAttached) {
+ mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+ }
+ }
+
+
/**
* Creates a new worker thread and saves the screenshot to the media store.
*/
@@ -378,14 +464,19 @@
return;
}
+ if (!isUserSetupComplete()) {
+ // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
+ // and sharing shouldn't be exposed to the user.
+ saveScreenshotAndToast(finisher);
+ return;
+ }
+
// Optimizations
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
- updateDarkTheme();
+ onConfigChanged(mContext.getResources().getConfiguration());
- mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
- mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
mDismissAnimation.cancel();
@@ -395,7 +486,6 @@
}
void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) {
- dismissScreenshot("new screenshot requested", true);
mOnCompleteRunnable = onComplete;
mDisplay.getRealMetrics(mDisplayMetrics);
@@ -407,7 +497,6 @@
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
Insets visibleInsets, int taskId, Consumer<Uri> finisher, Runnable onComplete) {
// TODO use taskId and visibleInsets
- dismissScreenshot("new screenshot requested", true);
mOnCompleteRunnable = onComplete;
takeScreenshot(screenshot, finisher, screenshotScreenBounds);
}
@@ -468,6 +557,41 @@
}
/**
+ * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
+ * failure).
+ */
+ private void saveScreenshotAndToast(Consumer<Uri> finisher) {
+ // Play the shutter sound to notify that we've taken a screenshot
+ mScreenshotHandler.post(() -> {
+ mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+ });
+
+ saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
+ @Override
+ void onActionsReady(SavedImageData imageData) {
+ finisher.accept(imageData.uri);
+ if (imageData.uri == null) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_capture_text);
+ } else {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
+
+ mScreenshotHandler.post(() -> {
+ Toast.makeText(mContext, R.string.screenshot_saved_title,
+ Toast.LENGTH_SHORT).show();
+ });
+ }
+ }
+ });
+ }
+
+ private boolean isUserSetupComplete() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+ }
+
+ /**
* Clears current screenshot
*/
private void dismissScreenshot(String reason, boolean immediate) {
@@ -513,53 +637,15 @@
}
/**
- * Update assets (called when the dark theme status changes). We only need to update the
- * dismiss
- * button and the actions container background, since the buttons are re-inflated on demand.
- */
- private void reloadAssets() {
- mDismissImage.setImageDrawable(mContext.getDrawable(R.drawable.screenshot_cancel));
- mActionsContainerBackground.setBackground(
- mContext.getDrawable(R.drawable.action_chip_container_background));
- }
-
- /**
- * Checks the current dark theme status and updates if it has changed.
- */
- private void updateDarkTheme() {
- int currentNightMode = mContext.getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK;
- switch (currentNightMode) {
- case Configuration.UI_MODE_NIGHT_NO:
- // Night mode is not active, we're using the light theme
- if (mInDarkMode) {
- mInDarkMode = false;
- reloadAssets();
- }
- break;
- case Configuration.UI_MODE_NIGHT_YES:
- // Night mode is active, we're using dark theme
- if (!mInDarkMode) {
- mInDarkMode = true;
- reloadAssets();
- }
- break;
- }
- }
-
- /**
* Starts the animation after taking the screenshot
*/
private void startAnimation(final Consumer<Uri> finisher, int w, int h,
@Nullable Rect screenRect) {
// If power save is on, show a toast so there is some visual indication that a
- // screenshot
- // has been taken.
- PowerManager powerManager = (PowerManager) mContext.getSystemService(
- Context.POWER_SERVICE);
+ // screenshot has been taken.
+ PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
if (powerManager.isPowerSaveMode()) {
- Toast.makeText(mContext, R.string.screenshot_saved_title,
- Toast.LENGTH_SHORT).show();
+ Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();
}
mScreenshotAnimation = createScreenshotDropInAnimation(w, h, screenRect);
@@ -588,31 +674,58 @@
} else {
createScreenshotActionsShadeAnimation(imageData).start();
}
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
+ SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS);
+
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
mScreenshotHandler.sendMessageDelayed(
mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
- SCREENSHOT_CORNER_TIMEOUT_MILLIS);
+ timeoutMs);
});
}
}
});
mScreenshotHandler.post(() -> {
- // Play the shutter sound to notify that we've taken a screenshot
- mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+ if (!mScreenshotLayout.isAttachedToWindow()) {
+ mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+ }
+ mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
- mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mScreenshotPreview.buildLayer();
- mScreenshotAnimation.start();
+ mScreenshotHandler.post(() -> {
+
+ // Play the shutter sound to notify that we've taken a screenshot
+ mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+
+ mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mScreenshotPreview.buildLayer();
+ mScreenshotAnimation.start();
+ });
+
});
+
}
private AnimatorSet createScreenshotDropInAnimation(int width, int height, Rect bounds) {
- float cornerScale = mCornerSizeX / (float) width;
+ float screenWidth = mDisplayMetrics.widthPixels;
+ float screenHeight = mDisplayMetrics.heightPixels;
- mScreenshotAnimatedView.setScaleX(1);
- mScreenshotAnimatedView.setScaleY(1);
- mScreenshotAnimatedView.setX(0);
- mScreenshotAnimatedView.setY(0);
+ int rotation = mContext.getDisplay().getRotation();
+ float cornerScale;
+ if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+ cornerScale = (mCornerSizeX / screenHeight);
+ } else {
+ cornerScale = (mCornerSizeX / screenWidth);
+ }
+ float currentScale = width / screenWidth;
+
+ mScreenshotAnimatedView.setScaleX(currentScale);
+ mScreenshotAnimatedView.setScaleY(currentScale);
+
+ mScreenshotAnimatedView.setPivotX(0);
+ mScreenshotAnimatedView.setPivotY(0);
mScreenshotAnimatedView.setImageBitmap(mScreenBitmap);
mScreenshotPreview.setImageBitmap(mScreenBitmap);
@@ -632,14 +745,12 @@
final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
float finalX;
- if (mContext.getResources().getConfiguration().getLayoutDirection()
- == View.LAYOUT_DIRECTION_LTR) {
- finalX = mScreenshotOffsetXPx + width * cornerScale / 2f;
+ if (mDirectionLTR) {
+ finalX = mScreenshotOffsetXPx + screenWidth * cornerScale / 2f;
} else {
- finalX = width - mScreenshotOffsetXPx - width * cornerScale / 2f;
+ finalX = screenWidth - mScreenshotOffsetXPx - screenWidth * cornerScale / 2f;
}
- float finalY =
- mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f;
+ float finalY = screenHeight - mScreenshotOffsetYPx - screenHeight * cornerScale / 2f;
final PointF finalPos = new PointF(finalX, finalY);
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
@@ -647,13 +758,12 @@
float xPositionPct =
SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
float scalePct =
- SCREENSHOT_TO_CORNER_SCALE_DURATION_MS
- / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
+ SCREENSHOT_TO_CORNER_SCALE_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
toCorner.addUpdateListener(animation -> {
float t = animation.getAnimatedFraction();
if (t < scalePct) {
float scale = MathUtils.lerp(
- 1, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct));
+ currentScale, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct));
mScreenshotAnimatedView.setScaleX(scale);
mScreenshotAnimatedView.setScaleY(scale);
} else {
@@ -667,13 +777,13 @@
if (t < xPositionPct) {
float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
mFastOutSlowIn.getInterpolation(t / xPositionPct));
- mScreenshotAnimatedView.setX(xCenter - width * currentScaleX / 2f);
+ mScreenshotAnimatedView.setX(xCenter - screenWidth * currentScaleX / 2f);
} else {
- mScreenshotAnimatedView.setX(finalPos.x - width * currentScaleX / 2f);
+ mScreenshotAnimatedView.setX(finalPos.x - screenWidth * currentScaleX / 2f);
}
float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
mFastOutSlowIn.getInterpolation(t));
- mScreenshotAnimatedView.setY(yCenter - height * currentScaleY / 2f);
+ mScreenshotAnimatedView.setY(yCenter - screenHeight * currentScaleY / 2f);
});
toCorner.addListener(new AnimatorListenerAdapter() {
@@ -713,7 +823,6 @@
private ValueAnimator createScreenshotActionsShadeAnimation(SavedImageData imageData) {
LayoutInflater inflater = LayoutInflater.from(mContext);
mActionsView.removeAllViews();
- mActionsContainer.setScrollX(0);
mScreenshotLayout.invalidate();
mScreenshotLayout.requestLayout();
mScreenshotLayout.getViewTreeObserver().dispatchOnGlobalLayout();
@@ -803,14 +912,11 @@
animator.setDuration(SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS);
float alphaFraction = (float) SCREENSHOT_ACTIONS_ALPHA_DURATION_MS
/ SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS;
- mActionsContainer.setVisibility(View.VISIBLE);
mActionsContainer.setAlpha(0f);
mActionsContainerBackground.setAlpha(0f);
+ mActionsContainer.setVisibility(View.VISIBLE);
mActionsContainerBackground.setVisibility(View.VISIBLE);
- mActionsContainer.setPivotX(0);
- mActionsContainerBackground.setPivotX(0);
-
animator.addUpdateListener(animation -> {
float t = animation.getAnimatedFraction();
mBackgroundProtection.setAlpha(t);
@@ -825,6 +931,10 @@
chip.setAlpha(t);
chip.setScaleX(1 / containerScale); // invert to keep size of children constant
}
+ mActionsContainer.setScrollX(mDirectionLTR ? 0 : mActionsContainer.getWidth());
+ mActionsContainer.setPivotX(mDirectionLTR ? 0 : mActionsContainer.getWidth());
+ mActionsContainerBackground.setPivotX(
+ mDirectionLTR ? 0 : mActionsContainerBackground.getWidth());
});
return animator;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 4f20492..f7f1223 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -92,7 +92,7 @@
}
private void handleDockKey(long shortcutCode) {
- if (mDivider == null || !mDivider.inSplitMode()) {
+ if (mDivider == null || !mDivider.isDividerVisible()) {
// Split the screen
mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index e67b3d7..cdd1280 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -16,6 +16,7 @@
package com.android.systemui.stackdivider;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
@@ -123,14 +124,17 @@
SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
sdl.rotateTo(toRotation);
mRotateSplitLayout = sdl;
- int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position
- : mView.getCurrentPosition();
+ 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 (inSplitMode()) {
+ if (isSplitActive()) {
WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
}
};
@@ -199,7 +203,7 @@
@Override
public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean imeShouldShow, SurfaceControl.Transaction t) {
- if (!inSplitMode()) {
+ if (!isDividerVisible()) {
return;
}
final boolean splitIsVisible = !mView.isHidden();
@@ -298,7 +302,7 @@
@Override
public void onImePositionChanged(int displayId, int imeTop,
SurfaceControl.Transaction t) {
- if (mAnimation != null || !inSplitMode() || mPaused) {
+ if (mAnimation != null || !isDividerVisible() || mPaused) {
// Not synchronized with IME anymore, so return.
return;
}
@@ -310,7 +314,7 @@
@Override
public void onImeEndPositioning(int displayId, boolean cancelled,
SurfaceControl.Transaction t) {
- if (mAnimation != null || !inSplitMode() || mPaused) {
+ if (mAnimation != null || !isDividerVisible() || mPaused) {
// Not synchronized with IME anymore, so return.
return;
}
@@ -479,7 +483,7 @@
@Override
public void onKeyguardShowingChanged() {
- if (!inSplitMode() || mView == null) {
+ if (!isDividerVisible() || mView == null) {
return;
}
mView.setHidden(mKeyguardStateController.isShowing());
@@ -559,10 +563,20 @@
}
/** {@code true} if this is visible */
- public boolean inSplitMode() {
+ 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.topActivityType != ACTIVITY_TYPE_UNDEFINED
+ || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED;
+ }
+
private void addDivider(Configuration configuration) {
Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
mView = (DividerView)
@@ -592,13 +606,11 @@
removeDivider();
addDivider(configuration);
- if (mView != null) {
- if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable);
- updateTouchable();
- }
- mView.setHidden(isDividerHidden);
+ if (mMinimized) {
+ mView.setMinimizedDockStack(true, mHomeStackResizable);
+ updateTouchable();
}
+ mView.setHidden(isDividerHidden);
}
void onTaskVanished() {
@@ -610,7 +622,7 @@
mContext.getDisplayId()).getResources().getConfiguration()));
}
- void updateVisibility(final boolean visible) {
+ private void updateVisibility(final boolean visible) {
if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
if (mVisible != visible) {
mVisible = visible;
@@ -637,8 +649,9 @@
}
void onSplitDismissed() {
- mMinimized = false;
updateVisibility(false /* visible */);
+ mMinimized = false;
+ removeDivider();
}
/** Switch to minimized state if appropriate */
@@ -656,7 +669,8 @@
private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
if (DEBUG) {
Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
- + mHomeStackResizable + "->" + homeStackResizable + " split:" + inSplitMode());
+ + mHomeStackResizable + "->" + homeStackResizable
+ + " split:" + isDividerVisible());
}
WindowContainerTransaction wct = new WindowContainerTransaction();
final boolean minimizedChanged = mMinimized != minimized;
@@ -671,7 +685,7 @@
final boolean homeResizableChanged = mHomeStackResizable != homeStackResizable;
if (homeResizableChanged) {
mHomeStackResizable = homeStackResizable;
- if (inSplitMode()) {
+ if (isDividerVisible()) {
WindowManagerProxy.applyHomeTasksMinimized(
mSplitLayout, mSplits.mSecondary.token, wct);
}
@@ -781,20 +795,22 @@
/** Register a listener that gets called whenever the existence of the divider changes */
public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- listener.accept(inSplitMode());
+ 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 = WindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
}
void ensureMinimizedSplit() {
setHomeMinimized(true /* minimized */, mSplits.mSecondary.isResizable());
- if (!inSplitMode()) {
+ if (!isDividerVisible()) {
// Wasn't in split-mode yet, so enter now.
if (DEBUG) {
Slog.d(TAG, " entering split mode with minimized=true");
@@ -805,7 +821,7 @@
void ensureNormalSplit() {
setHomeMinimized(false /* minimized */, mHomeStackResizable);
- if (!inSplitMode()) {
+ if (!isDividerVisible()) {
// Wasn't in split-mode, so enter now.
if (DEBUG) {
Slog.d(TAG, " enter split mode unminimized ");
@@ -813,4 +829,12 @@
updateVisibility(true /* visible */);
}
}
+
+ /** @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/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 060760a..db89cea 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -28,12 +28,14 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
+import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Slog;
import android.view.Display;
@@ -164,6 +166,9 @@
int mDividerPositionX;
int mDividerPositionY;
+ private final Matrix mTmpMatrix = new Matrix();
+ private final float[] mTmpValues = new float[9];
+
// The view is removed or in the process of been removed from the system.
private boolean mRemoved;
@@ -249,6 +254,22 @@
}
};
+ private Runnable mUpdateEmbeddedMatrix = () -> {
+ if (getViewRootImpl() == null) {
+ return;
+ }
+ if (isHorizontalDivision()) {
+ mTmpMatrix.setTranslate(0, mDividerPositionY - mDividerInsets);
+ } else {
+ mTmpMatrix.setTranslate(mDividerPositionX - mDividerInsets, 0);
+ }
+ mTmpMatrix.getValues(mTmpValues);
+ try {
+ getViewRootImpl().getAccessibilityEmbeddedConnection().setScreenMatrix(mTmpValues);
+ } catch (RemoteException e) {
+ }
+ };
+
public DividerView(Context context) {
this(context, null);
}
@@ -1084,6 +1105,10 @@
t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
}
}
+ if (getViewRootImpl() != null) {
+ mHandler.removeCallbacks(mUpdateEmbeddedMatrix);
+ mHandler.post(mUpdateEmbeddedMatrix);
+ }
}
void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 2862c83..c496d22 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -193,7 +193,7 @@
Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
+ " " + mSecondary.topActivityType);
}
- if (mDivider.inSplitMode()) {
+ if (mDivider.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) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
new file mode 100644
index 0000000..7f7ff9cf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
@@ -0,0 +1,88 @@
+/*
+ * 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
+
+import android.app.PendingIntent
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotifInteractionLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import javax.inject.Inject
+
+/**
+ * Logger class for events related to the user clicking on notification actions
+ */
+class ActionClickLogger @Inject constructor(
+ @NotifInteractionLog private val buffer: LogBuffer
+) {
+ fun logInitialClick(
+ entry: NotificationEntry?,
+ pendingIntent: PendingIntent
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = entry?.key
+ str2 = entry?.ranking?.channel?.id
+ str3 = pendingIntent.intent.toString()
+ }, {
+ "ACTION CLICK $str1 (channel=$str2) for pending intent $str3"
+ })
+ }
+
+ fun logRemoteInputWasHandled(
+ entry: NotificationEntry?
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = entry?.key
+ }, {
+ " [Action click] Triggered remote input (for $str1))"
+ })
+ }
+
+ fun logStartingIntentWithDefaultHandler(
+ entry: NotificationEntry?,
+ pendingIntent: PendingIntent
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = entry?.key
+ str2 = pendingIntent.intent.toString()
+ }, {
+ " [Action click] Launching intent $str2 via default handler (for $str1)"
+ })
+ }
+
+ fun logWaitingToCloseKeyguard(
+ pendingIntent: PendingIntent
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = pendingIntent.intent.toString()
+ }, {
+ " [Action click] Intent $str1 launches an activity, dismissing keyguard first..."
+ })
+ }
+
+ fun logKeyguardGone(
+ pendingIntent: PendingIntent
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = pendingIntent.intent.toString()
+ }, {
+ " [Action click] Keyguard dismissed, calling default handler for intent $str1"
+ })
+ }
+}
+
+private const val TAG = "ActionClickLogger"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 2419515..96d6ecb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -263,7 +263,7 @@
default void showAuthenticationDialog(Bundle bundle,
IBiometricServiceReceiverInternal receiver, int biometricModality,
boolean requireConfirmation, int userId, String opPackageName,
- long operationId) { }
+ long operationId, int sysUiSessionId) { }
default void onBiometricAuthenticated() { }
default void onBiometricHelp(String message) { }
default void onBiometricError(int modality, int error, int vendorCode) { }
@@ -782,7 +782,7 @@
@Override
public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, int sysUiSessionId) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -792,6 +792,7 @@
args.argi2 = userId;
args.arg4 = opPackageName;
args.arg5 = operationId;
+ args.argi3 = sysUiSessionId;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
}
@@ -1169,7 +1170,8 @@
(boolean) someArgs.arg3 /* requireConfirmation */,
someArgs.argi2 /* userId */,
(String) someArgs.arg4 /* opPackageName */,
- (long) someArgs.arg5 /* operationId */);
+ (long) someArgs.arg5 /* operationId */,
+ someArgs.argi3 /* sysUiSessionId */);
}
someArgs.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 2647c04..2baab61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -19,8 +19,8 @@
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import android.app.ActivityManager;
import android.app.KeyguardManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index e32d174..9f4932e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -44,14 +44,17 @@
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
+
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.keyguard.KeyguardMediaPlayer;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.media.MediaData;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -113,7 +116,6 @@
private ScrimController mScrimController;
@Nullable
private LockscreenWallpaper mLockscreenWallpaper;
- private final KeyguardMediaPlayer mMediaPlayer;
private final Executor mMainExecutor;
@@ -187,13 +189,12 @@
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
KeyguardBypassController keyguardBypassController,
- KeyguardMediaPlayer keyguardMediaPlayer,
@Main Executor mainExecutor,
- DeviceConfigProxy deviceConfig) {
+ DeviceConfigProxy deviceConfig,
+ MediaDataManager mediaDataManager) {
mContext = context;
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
- mMediaPlayer = keyguardMediaPlayer;
mMediaListeners = new ArrayList<>();
// TODO: use MediaSessionManager.SessionListener to hook us up to future updates
// in session state
@@ -204,14 +205,26 @@
mNotificationShadeWindowController = notificationShadeWindowController;
mEntryManager = notificationEntryManager;
mMainExecutor = mainExecutor;
+
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
- findAndUpdateMediaNotifications();
+ mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
+ mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
+ }
+
+ @Override
+ public void onEntryInflated(NotificationEntry entry) {
+ findAndUpdateMediaNotifications();
+ }
+
+ @Override
+ public void onEntryReinflated(NotificationEntry entry) {
findAndUpdateMediaNotifications();
}
@@ -222,6 +235,7 @@
boolean removedByUser,
int reason) {
onNotificationRemoved(entry.getKey());
+ mediaDataManager.onNotificationRemoved(entry.getKey());
}
});
@@ -278,7 +292,7 @@
public void addCallback(MediaListener callback) {
mMediaListeners.add(callback);
- callback.onMetadataOrStateChanged(mMediaMetadata,
+ callback.onPrimaryMetadataOrStateChanged(mMediaMetadata,
getMediaControllerPlaybackState(mMediaController));
}
@@ -392,7 +406,7 @@
@PlaybackState.State int state = getMediaControllerPlaybackState(mMediaController);
ArrayList<MediaListener> callbacks = new ArrayList<>(mMediaListeners);
for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).onMetadataOrStateChanged(mMediaMetadata, state);
+ callbacks.get(i).onPrimaryMetadataOrStateChanged(mMediaMetadata, state);
}
}
@@ -473,7 +487,6 @@
&& mBiometricUnlockController.isWakeAndUnlock();
if (mKeyguardStateController.isLaunchTransitionFadingAway() || wakeAndUnlock) {
mBackdrop.setVisibility(View.INVISIBLE);
- mMediaPlayer.clearControls();
Trace.endSection();
return;
}
@@ -496,14 +509,6 @@
}
}
- NotificationEntry entry = mEntryManager
- .getActiveNotificationUnfiltered(mMediaNotificationKey);
- if (entry != null) {
- mMediaPlayer.updateControls(entry, getMediaIcon(), mediaMetadata);
- } else {
- mMediaPlayer.clearControls();
- }
-
// Process artwork on a background thread and send the resulting bitmap to
// finishUpdateMediaMetaData.
if (metaDataChanged) {
@@ -626,7 +631,6 @@
// We are unlocking directly - no animation!
mBackdrop.setVisibility(View.GONE);
mBackdropBack.setImageDrawable(null);
- mMediaPlayer.clearControls();
if (windowController != null) {
windowController.setBackdropShowing(false);
}
@@ -643,7 +647,6 @@
mBackdrop.setVisibility(View.GONE);
mBackdropFront.animate().cancel();
mBackdropBack.setImageDrawable(null);
- mMediaPlayer.clearControls();
mMainExecutor.execute(mHideBackdropFront);
});
if (mKeyguardStateController.isKeyguardFadingAway()) {
@@ -750,6 +753,7 @@
* @param state Current playback state
* @see PlaybackState.State
*/
- void onMetadataOrStateChanged(MediaMetadata metadata, @PlaybackState.State int state);
+ default void onPrimaryMetadataOrStateChanged(MediaMetadata metadata,
+ @PlaybackState.State int state) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 3cb2a2a..1079f10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -52,7 +52,7 @@
/**
* Updates the visual representation of the notifications.
*/
- void updateNotificationViews();
+ void updateNotificationViews(String reason);
/**
* Returns the maximum number of notifications to show while locked.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index bf28040..9181c69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -54,7 +54,7 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.dagger.StatusBarModule;
+import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -114,6 +114,7 @@
private final SmartReplyController mSmartReplyController;
private final NotificationEntryManager mEntryManager;
private final Handler mMainHandler;
+ private final ActionClickLogger mLogger;
private final Lazy<StatusBar> mStatusBarLazy;
@@ -138,14 +139,18 @@
mStatusBarLazy.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
"NOTIFICATION_CLICK");
+ final NotificationEntry entry = getNotificationForParent(view.getParent());
+ mLogger.logInitialClick(entry, pendingIntent);
+
if (handleRemoteInput(view, pendingIntent)) {
+ mLogger.logRemoteInputWasHandled(entry);
return true;
}
if (DEBUG) {
Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
}
- logActionClick(view, pendingIntent);
+ logActionClick(view, entry, pendingIntent);
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
@@ -158,11 +163,15 @@
Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
options.second.setLaunchWindowingMode(
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ mLogger.logStartingIntentWithDefaultHandler(entry, pendingIntent);
return RemoteViews.startPendingIntent(view, pendingIntent, options);
});
}
- private void logActionClick(View view, PendingIntent actionIntent) {
+ private void logActionClick(
+ View view,
+ NotificationEntry entry,
+ PendingIntent actionIntent) {
Integer actionIndex = (Integer)
view.getTag(com.android.internal.R.id.notification_action_index_tag);
if (actionIndex == null) {
@@ -170,7 +179,7 @@
return;
}
ViewParent parent = view.getParent();
- StatusBarNotification statusBarNotification = getNotificationForParent(parent);
+ StatusBarNotification statusBarNotification = entry.getSbn();
if (statusBarNotification == null) {
Log.w(TAG, "Couldn't determine notification for click.");
return;
@@ -212,10 +221,10 @@
}
}
- private StatusBarNotification getNotificationForParent(ViewParent parent) {
+ private NotificationEntry getNotificationForParent(ViewParent parent) {
while (parent != null) {
if (parent instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) parent).getEntry().getSbn();
+ return ((ExpandableNotificationRow) parent).getEntry();
}
parent = parent.getParent();
}
@@ -255,7 +264,7 @@
};
/**
- * Injected constructor. See {@link StatusBarModule}.
+ * Injected constructor. See {@link StatusBarDependenciesModule}.
*/
public NotificationRemoteInputManager(
Context context,
@@ -265,13 +274,15 @@
Lazy<StatusBar> statusBarLazy,
StatusBarStateController statusBarStateController,
@Main Handler mainHandler,
- RemoteInputUriController remoteInputUriController) {
+ RemoteInputUriController remoteInputUriController,
+ ActionClickLogger logger) {
mContext = context;
mLockscreenUserManager = lockscreenUserManager;
mSmartReplyController = smartReplyController;
mEntryManager = notificationEntryManager;
mStatusBarLazy = statusBarLazy;
mMainHandler = mainHandler;
+ mLogger = logger;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 8fcc67a..3dda15b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -184,21 +184,25 @@
mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow());
boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn());
- boolean groupChangesAllowed = mVisualStabilityManager.areGroupChangesAllowed()
- || !ent.hasFinishedInitialization();
+ boolean groupChangesAllowed =
+ mVisualStabilityManager.areGroupChangesAllowed() // user isn't looking at notifs
+ || !ent.hasFinishedInitialization(); // notif recently added
+
NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn());
if (!groupChangesAllowed) {
// We don't to change groups while the user is looking at them
boolean wasChildInGroup = ent.isChildInGroup();
if (isChildInGroup && !wasChildInGroup) {
isChildInGroup = wasChildInGroup;
- mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
+ mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager,
+ false /* persistent */);
} else if (!isChildInGroup && wasChildInGroup) {
// We allow grouping changes if the group was collapsed
if (mGroupManager.isLogicalGroupExpanded(ent.getSbn())) {
isChildInGroup = wasChildInGroup;
parent = ent.getRow().getNotificationParent().getEntry();
- mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
+ mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager,
+ false /* persistent */);
}
}
}
@@ -283,7 +287,8 @@
if (mVisualStabilityManager.canReorderNotification(targetChild)) {
mListContainer.changeViewPosition(targetChild, i);
} else {
- mVisualStabilityManager.addReorderingAllowedCallback(mEntryManager);
+ mVisualStabilityManager.addReorderingAllowedCallback(mEntryManager,
+ false /* persistent */);
}
}
j++;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScreenRecordDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScreenRecordDrawable.java
index 44ef6b4..006b219 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScreenRecordDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScreenRecordDrawable.java
@@ -39,10 +39,13 @@
*/
public class ScreenRecordDrawable extends DrawableWrapper {
private Drawable mFillDrawable;
+ private Drawable mIconDrawable;
private int mHorizontalPadding;
private int mLevel;
private float mTextSize;
- private float mIconRadius;
+ private int mIconRadius;
+ private int mWidthPx;
+ private int mHeightPx;
private Paint mPaint;
/** No-arg constructor used by drawable inflation. */
@@ -57,6 +60,7 @@
super.inflate(r, parser, attrs, theme);
setDrawable(r.getDrawable(R.drawable.ic_screen_record_background, theme).mutate());
mFillDrawable = r.getDrawable(R.drawable.ic_screen_record_background, theme).mutate();
+ mIconDrawable = r.getDrawable(R.drawable.ic_screenrecord, theme).mutate();
mHorizontalPadding = r.getDimensionPixelSize(R.dimen.status_bar_horizontal_padding);
mTextSize = r.getDimensionPixelSize(R.dimen.screenrecord_status_text_size);
@@ -68,6 +72,19 @@
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(mTextSize);
mPaint.setFakeBoldText(true);
+
+ mWidthPx = r.getDimensionPixelSize(R.dimen.screenrecord_status_icon_width);
+ mHeightPx = r.getDimensionPixelSize(R.dimen.screenrecord_status_icon_height);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidthPx;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeightPx;
}
@Override
@@ -103,10 +120,14 @@
String val = String.valueOf(mLevel);
Rect textBounds = new Rect();
mPaint.getTextBounds(val, 0, val.length(), textBounds);
- float yOffset = textBounds.height() / 4; // half, and half again since it's centered
- canvas.drawText(val, b.centerX(), b.centerY() + yOffset, mPaint);
+ canvas.drawText(val, b.centerX(), b.centerY() + textBounds.height() / 2, mPaint);
} else {
- canvas.drawCircle(b.centerX(), b.centerY() - mIconRadius / 2, mIconRadius, mPaint);
+ Rect iconBounds = new Rect(b.centerX() - mIconRadius,
+ b.centerY() - mIconRadius,
+ b.centerX() + mIconRadius,
+ b.centerY() + mIconRadius);
+ mIconDrawable.setBounds(iconBounds);
+ mIconDrawable.draw(canvas);
}
}
@@ -114,9 +135,6 @@
public boolean getPadding(Rect padding) {
padding.left += mHorizontalPadding;
padding.right += mHorizontalPadding;
- padding.top = 0;
- padding.bottom = 0;
- android.util.Log.d("ScreenRecordDrawable", "set zero top/bottom pad");
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index de7e36d9..b08eb9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -21,10 +21,11 @@
import android.os.Handler;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.keyguard.KeyguardMediaPlayer;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.MediaArtworkProcessor;
import com.android.systemui.statusbar.NotificationListener;
@@ -73,7 +74,8 @@
Lazy<StatusBar> statusBarLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
- RemoteInputUriController remoteInputUriController) {
+ RemoteInputUriController remoteInputUriController,
+ ActionClickLogger actionClickLogger) {
return new NotificationRemoteInputManager(
context,
lockscreenUserManager,
@@ -82,7 +84,8 @@
statusBarLazy,
statusBarStateController,
mainHandler,
- remoteInputUriController);
+ remoteInputUriController,
+ actionClickLogger);
}
/** */
@@ -95,9 +98,9 @@
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
KeyguardBypassController keyguardBypassController,
- KeyguardMediaPlayer keyguardMediaPlayer,
@Main Executor mainExecutor,
- DeviceConfigProxy deviceConfigProxy) {
+ DeviceConfigProxy deviceConfigProxy,
+ MediaDataManager mediaDataManager) {
return new NotificationMediaManager(
context,
statusBarLazy,
@@ -105,9 +108,9 @@
notificationEntryManager,
mediaArtworkProcessor,
keyguardBypassController,
- keyguardMediaPlayer,
mainExecutor,
- deviceConfigProxy);
+ deviceConfigProxy,
+ mediaDataManager);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
index 75b41ca..eee9cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar.notification;
+import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
+import android.util.Log;
import android.util.Property;
import android.view.View;
@@ -35,6 +37,100 @@
public static final AnimatableProperty Y = AnimatableProperty.from(View.Y,
R.id.y_animator_tag, R.id.y_animator_tag_start_value, R.id.y_animator_tag_end_value);
+ /**
+ * Similar to X, however this doesn't allow for any other modifications other than from this
+ * property. When using X, it's possible that the view is laid out during the animation,
+ * which could break the continuity
+ */
+ public static final AnimatableProperty ABSOLUTE_X = AnimatableProperty.from(
+ new FloatProperty<View>("ViewAbsoluteX") {
+ @Override
+ public void setValue(View view, float value) {
+ view.setTag(R.id.absolute_x_current_value, value);
+ View.X.set(view, value);
+ }
+
+ @Override
+ public Float get(View view) {
+ Object tag = view.getTag(R.id.absolute_x_current_value);
+ if (tag instanceof Float) {
+ return (Float) tag;
+ }
+ return View.X.get(view);
+ }
+ },
+ R.id.absolute_x_animator_tag,
+ R.id.absolute_x_animator_start_tag,
+ R.id.absolute_x_animator_end_tag);
+
+ /**
+ * Similar to Y, however this doesn't allow for any other modifications other than from this
+ * property. When using X, it's possible that the view is laid out during the animation,
+ * which could break the continuity
+ */
+ public static final AnimatableProperty ABSOLUTE_Y = AnimatableProperty.from(
+ new FloatProperty<View>("ViewAbsoluteY") {
+ @Override
+ public void setValue(View view, float value) {
+ view.setTag(R.id.absolute_y_current_value, value);
+ View.Y.set(view, value);
+ }
+
+ @Override
+ public Float get(View view) {
+ Object tag = view.getTag(R.id.absolute_y_current_value);
+ if (tag instanceof Float) {
+ return (Float) tag;
+ }
+ return View.Y.get(view);
+ }
+ },
+ R.id.absolute_y_animator_tag,
+ R.id.absolute_y_animator_start_tag,
+ R.id.absolute_y_animator_end_tag);
+
+ public static final AnimatableProperty WIDTH = AnimatableProperty.from(
+ new FloatProperty<View>("ViewWidth") {
+ @Override
+ public void setValue(View view, float value) {
+ view.setTag(R.id.view_width_current_value, value);
+ view.setRight((int) (view.getLeft() + value));
+ }
+
+ @Override
+ public Float get(View view) {
+ Object tag = view.getTag(R.id.view_width_current_value);
+ if (tag instanceof Float) {
+ return (Float) tag;
+ }
+ return (float) view.getWidth();
+ }
+ },
+ R.id.view_width_animator_tag,
+ R.id.view_width_animator_start_tag,
+ R.id.view_width_animator_end_tag);
+
+ public static final AnimatableProperty HEIGHT = AnimatableProperty.from(
+ new FloatProperty<View>("ViewHeight") {
+ @Override
+ public void setValue(View view, float value) {
+ view.setTag(R.id.view_height_current_value, value);
+ view.setBottom((int) (view.getTop() + value));
+ }
+
+ @Override
+ public Float get(View view) {
+ Object tag = view.getTag(R.id.view_height_current_value);
+ if (tag instanceof Float) {
+ return (Float) tag;
+ }
+ return (float) view.getHeight();
+ }
+ },
+ R.id.view_height_animator_tag,
+ R.id.view_height_animator_start_tag,
+ R.id.view_height_animator_end_tag);
+
public abstract int getAnimationStartTag();
public abstract int getAnimationEndTag();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 55a20fa..040dbe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -288,7 +288,7 @@
mContext,
0,
new Intent(Intent.ACTION_VIEW).setData(Uri.parse(helpUrl)),
- 0,
+ PendingIntent.FLAG_IMMUTABLE,
null,
user)
: null;
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 f1cb783..d647124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -440,6 +440,10 @@
mLogger.logLifetimeExtended(key, extender.getClass().getName(), "pending");
}
}
+ if (!lifetimeExtended) {
+ // At this point, we are guaranteed the notification will be removed
+ mAllNotifications.remove(pendingEntry);
+ }
}
}
@@ -670,7 +674,7 @@
public void updateNotifications(String reason) {
reapplyFilterAndSort(reason);
if (mPresenter != null && !mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mPresenter.updateNotificationViews();
+ mPresenter.updateNotificationViews(reason);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index e2b01ff..ce6013f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -21,11 +21,12 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_MEDIA_CONTROLS
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
+import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
+import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS
+import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.Utils
@@ -52,12 +53,14 @@
fun getNotificationBuckets(): IntArray {
return when {
isFilteringEnabled() && isMediaControlsEnabled() ->
- intArrayOf(BUCKET_HEADS_UP, BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_ALERTING,
- BUCKET_SILENT)
+ intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
+ BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
!isFilteringEnabled() && isMediaControlsEnabled() ->
- intArrayOf(BUCKET_HEADS_UP, BUCKET_MEDIA_CONTROLS, BUCKET_ALERTING, BUCKET_SILENT)
+ intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
+ BUCKET_ALERTING, BUCKET_SILENT)
isFilteringEnabled() && !isMediaControlsEnabled() ->
- intArrayOf(BUCKET_HEADS_UP, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
+ intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_PEOPLE,
+ BUCKET_ALERTING, BUCKET_SILENT)
NotificationUtils.useNewInterruptionModel(context) ->
intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
else ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index 1f9d3af..3517e24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -34,13 +34,20 @@
*/
public class PropertyAnimator {
+ /**
+ * Set a property on a view, updating its value, even if it's already animating.
+ * The @param animated can be used to request an animation.
+ * If the view isn't animated, this utility will update the current animation if existent,
+ * such that the end value will point to @param newEndValue or apply it directly if there's
+ * no animation.
+ */
public static <T extends View> void setProperty(final T view,
AnimatableProperty animatableProperty, float newEndValue,
AnimationProperties properties, boolean animated) {
int animatorTag = animatableProperty.getAnimatorTag();
ValueAnimator previousAnimator = ViewState.getChildTag(view, animatorTag);
if (previousAnimator != null || animated) {
- startAnimation(view, animatableProperty, newEndValue, properties);
+ startAnimation(view, animatableProperty, newEndValue, animated ? properties : null);
} else {
// no new animation needed, let's just apply the value
animatableProperty.getProperty().set(view, newEndValue);
@@ -60,8 +67,8 @@
}
int animatorTag = animatableProperty.getAnimatorTag();
ValueAnimator previousAnimator = ViewState.getChildTag(view, animatorTag);
- AnimationFilter filter = properties.getAnimationFilter();
- if (!filter.shouldAnimateProperty(property)) {
+ AnimationFilter filter = properties != null ? properties.getAnimationFilter() : null;
+ if (filter == null || !filter.shouldAnimateProperty(property)) {
// just a local update was performed
if (previousAnimator != null) {
// we need to increase all animation keyframes of the previous animator by the
@@ -82,6 +89,17 @@
}
Float currentValue = property.get(view);
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(property);
+ if (currentValue.equals(newEndValue)) {
+ // Skip the animation!
+ if (previousAnimator != null) {
+ previousAnimator.cancel();
+ }
+ if (listener != null) {
+ listener.onAnimationEnd(null);
+ }
+ return;
+ }
ValueAnimator animator = ValueAnimator.ofFloat(currentValue, newEndValue);
animator.addUpdateListener(
animation -> property.set(view, (Float) animation.getAnimatedValue()));
@@ -96,7 +114,6 @@
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener(property);
if (listener != null) {
animator.addListener(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 7ac5995..8341c02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -43,7 +43,9 @@
private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000;
private final ArrayList<Callback> mReorderingAllowedCallbacks = new ArrayList<>();
+ private final ArraySet<Callback> mPersistentReorderingCallbacks = new ArraySet<>();
private final ArrayList<Callback> mGroupChangesAllowedCallbacks = new ArrayList<>();
+ private final ArraySet<Callback> mPersistentGroupCallbacks = new ArraySet<>();
private final Handler mHandler;
private boolean mPanelExpanded;
@@ -85,8 +87,15 @@
/**
* Add a callback to invoke when reordering is allowed again.
+ *
+ * @param callback the callback to add
+ * @param persistent {@code true} if this callback should this callback be persisted, otherwise
+ * it will be removed after a single invocation
*/
- public void addReorderingAllowedCallback(Callback callback) {
+ public void addReorderingAllowedCallback(Callback callback, boolean persistent) {
+ if (persistent) {
+ mPersistentReorderingCallbacks.add(callback);
+ }
if (mReorderingAllowedCallbacks.contains(callback)) {
return;
}
@@ -95,8 +104,15 @@
/**
* Add a callback to invoke when group changes are allowed again.
+ *
+ * @param callback the callback to add
+ * @param persistent {@code true} if this callback should this callback be persisted, otherwise
+ * it will be removed after a single invocation
*/
- public void addGroupChangesAllowedCallback(Callback callback) {
+ public void addGroupChangesAllowedCallback(Callback callback, boolean persistent) {
+ if (persistent) {
+ mPersistentGroupCallbacks.add(callback);
+ }
if (mGroupChangesAllowedCallbacks.contains(callback)) {
return;
}
@@ -136,21 +152,26 @@
boolean changedToTrue = reorderingAllowed && !mReorderingAllowed;
mReorderingAllowed = reorderingAllowed;
if (changedToTrue) {
- notifyChangeAllowed(mReorderingAllowedCallbacks);
+ notifyChangeAllowed(mReorderingAllowedCallbacks, mPersistentReorderingCallbacks);
}
boolean groupChangesAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
changedToTrue = groupChangesAllowed && !mGroupChangedAllowed;
mGroupChangedAllowed = groupChangesAllowed;
if (changedToTrue) {
- notifyChangeAllowed(mGroupChangesAllowedCallbacks);
+ notifyChangeAllowed(mGroupChangesAllowedCallbacks, mPersistentGroupCallbacks);
}
}
- private void notifyChangeAllowed(ArrayList<Callback> callbacks) {
+ private void notifyChangeAllowed(ArrayList<Callback> callbacks,
+ ArraySet<Callback> persistentCallbacks) {
for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).onChangeAllowed();
+ Callback callback = callbacks.get(i);
+ callback.onChangeAllowed();
+ if (!persistentCallbacks.contains(callback)) {
+ callbacks.remove(callback);
+ i--;
+ }
}
- callbacks.clear();
}
/**
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 cb0c283..1eadd9e 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
@@ -31,7 +31,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
import static java.util.Objects.requireNonNull;
@@ -68,7 +68,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
+import com.android.systemui.statusbar.notification.stack.PriorityBucket;
import java.util.ArrayList;
import java.util.List;
@@ -151,6 +151,8 @@
public CharSequence headsUpStatusBarText;
public CharSequence headsUpStatusBarTextPublic;
+ // indicates when this entry's view was first attached to a window
+ // this value will reset when the view is completely removed from the shade (ie: filtered out)
private long initializationTime = -1;
/**
@@ -209,7 +211,7 @@
}
/** The key for this notification. Guaranteed to be immutable and unique */
- public String getKey() {
+ @NonNull public String getKey() {
return mKey;
}
@@ -217,7 +219,7 @@
* The StatusBarNotification that represents one half of a NotificationEntry (the other half
* being the Ranking). This object is swapped out whenever a notification is updated.
*/
- public StatusBarNotification getSbn() {
+ @NonNull public StatusBarNotification getSbn() {
return mSbn;
}
@@ -409,12 +411,12 @@
return wasBubble != isBubble();
}
- @NotificationSectionsManager.PriorityBucket
+ @PriorityBucket
public int getBucket() {
return mBucket;
}
- public void setBucket(@NotificationSectionsManager.PriorityBucket int bucket) {
+ public void setBucket(@PriorityBucket int bucket) {
mBucket = bucket;
}
@@ -473,8 +475,8 @@
}
public boolean hasFinishedInitialization() {
- return initializationTime == -1
- || SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
+ return initializationTime != -1
+ && SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
}
public int getContrastedColor(Context context, boolean isLowPriority,
@@ -565,6 +567,10 @@
return false;
}
+ public void resetInitializationTime() {
+ initializationTime = -1;
+ }
+
public void setInitializationTime(long time) {
if (initializationTime == -1) {
initializationTime = time;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 9738bcc..dc0b802 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -27,20 +27,17 @@
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
-
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
+import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
+import com.android.systemui.statusbar.notification.stack.PriorityBucket
import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Lazy
-import java.util.Objects;
+import java.util.Objects
import javax.inject.Inject
-import kotlin.Comparator
private const val TAG = "NotifRankingManager"
@@ -137,36 +134,35 @@
): List<NotificationEntry> {
logger.logFilterAndSort(reason)
val filtered = entries.asSequence()
- .filterNot(notifFilter::shouldFilterOut)
+ .filterNot(this::filter)
.sortedWith(rankingComparator)
.toList()
- for (entry in filtered) {
- assignBucketForEntry(entry)
+ entries.forEach { it.bucket = getBucketForEntry(it) }
+ return filtered
+ }
+
+ private fun filter(entry: NotificationEntry): Boolean {
+ val filtered = notifFilter.shouldFilterOut(entry)
+ if (filtered) {
+ // notification is removed from the list, so we reset its initialization time
+ entry.resetInitializationTime()
}
return filtered
}
- private fun assignBucketForEntry(entry: NotificationEntry) {
+ @PriorityBucket
+ private fun getBucketForEntry(entry: NotificationEntry): Int {
val isHeadsUp = entry.isRowHeadsUp
val isMedia = isImportantMedia(entry)
val isSystemMax = entry.isSystemMax()
- setBucket(entry, isHeadsUp, isMedia, isSystemMax)
- }
-
- private fun setBucket(
- entry: NotificationEntry,
- isHeadsUp: Boolean,
- isMedia: Boolean,
- isSystemMax: Boolean
- ) {
- if (usePeopleFiltering && isHeadsUp) {
- entry.bucket = BUCKET_HEADS_UP
- } else if (usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON) {
- entry.bucket = BUCKET_PEOPLE
- } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
- entry.bucket = BUCKET_ALERTING
- } else {
- entry.bucket = BUCKET_SILENT
+ return when {
+ entry.sbn.notification.isForegroundService && entry.sbn.notification.isColorized ->
+ BUCKET_FOREGROUND_SERVICE
+ usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON ->
+ BUCKET_PEOPLE
+ isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() ->
+ BUCKET_ALERTING
+ else -> BUCKET_SILENT
}
}
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 0a3b02c..4cec383 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
@@ -713,6 +713,10 @@
private boolean applyFilters(NotificationEntry entry, long now, List<NotifFilter> filters) {
final NotifFilter filter = findRejectingFilter(entry, now, filters);
entry.getAttachState().setExcludingFilter(filter);
+ if (filter != null) {
+ // notification is removed from the list, so we reset its initialization time
+ entry.resetInitializationTime();
+ }
return filter != null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
index 1c1b2bb..a0f9dc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
@@ -28,10 +28,9 @@
@Singleton
class TargetSdkResolver @Inject constructor(
- private val context: Context,
- private val collection: CommonNotifCollection
+ private val context: Context
) {
- init {
+ fun initialize(collection: CommonNotifCollection) {
collection.addCollectionListener(object : NotifCollectionListener {
override fun onEntryBind(entry: NotificationEntry, sbn: StatusBarNotification) {
entry.targetSdk = resolveNotificationSdk(sbn)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
index 59f119e..3fab6f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.notifcollection;
+import android.annotation.NonNull;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -43,13 +44,13 @@
* there is no guarantee of order and they may not have had a chance to initialize yet. Instead,
* use {@link #onEntryAdded} which is called after all initialization.
*/
- default void onEntryInit(NotificationEntry entry) {
+ default void onEntryInit(@NonNull NotificationEntry entry) {
}
/**
* Called whenever a notification with a new key is posted.
*/
- default void onEntryAdded(NotificationEntry entry) {
+ default void onEntryAdded(@NonNull NotificationEntry entry) {
}
/**
@@ -64,7 +65,7 @@
* immediately after a user dismisses a notification: we wait until we receive confirmation from
* system server before considering the notification removed.
*/
- default void onEntryRemoved(NotificationEntry entry, @CancellationReason int reason) {
+ default void onEntryRemoved(@NonNull NotificationEntry entry, @CancellationReason int reason) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index c975404..6e4fcd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -25,8 +25,10 @@
import com.android.systemui.statusbar.notification.NotificationClicker
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.NotificationListController
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
+import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
import com.android.systemui.statusbar.notification.interruption.HeadsUpController
import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -56,6 +58,8 @@
private val featureFlags: FeatureFlags,
private val notificationListener: NotificationListener,
private val entryManager: NotificationEntryManager,
+ private val notifPipeline: Lazy<NotifPipeline>,
+ private val targetSdkResolver: TargetSdkResolver,
private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
private val notifBindPipelineInitializer: NotifBindPipelineInitializer,
private val deviceProvisionedController: DeviceProvisionedController,
@@ -102,8 +106,10 @@
}
if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ targetSdkResolver.initialize(notifPipeline.get())
// TODO
} else {
+ targetSdkResolver.initialize(entryManager)
remoteInputUriController.attach(entryManager)
groupAlertTransferHelper.bind(entryManager, groupManager)
headsUpManager.addListener(groupManager)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
index 88888d1..0fd865b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
@@ -75,7 +75,7 @@
mediaManager.addCallback(this)
}
- override fun onMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
+ override fun onPrimaryMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
val previous = currentMediaEntry
var newEntry = entryManager
.getActiveNotificationUnfiltered(mediaManager.mediaNotificationKey)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
index 29447ca..cc917dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
@@ -18,6 +18,7 @@
import android.annotation.MainThread;
import android.util.ArrayMap;
+import android.util.Log;
import androidx.annotation.NonNull;
@@ -66,8 +67,10 @@
public final Params getStageParams(@NonNull NotificationEntry entry) {
Params params = mContentParams.get(entry);
if (params == null) {
- throw new IllegalStateException(
- String.format("Entry does not have any stage parameters. key: %s",
+ // TODO: This should throw an exception but there are some cases of re-entrant calls
+ // in NotificationEntryManager (e.g. b/155324756) that cause removal in update that
+ // lead to inflation after the notification is "removed".
+ Log.wtf(TAG, String.format("Entry does not have any stage parameters. key: %s",
entry.getKey()));
}
return params;
@@ -92,6 +95,8 @@
*/
protected abstract Params newStageParams();
+ private static final String TAG = "BindStage";
+
/**
* Interface for callback.
*/
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 2e5af9a..f7ad50e 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
@@ -2366,6 +2366,11 @@
updateChildrenVisibility();
applyChildrenRoundness();
}
+
+ protected void expandNotification() {
+ mExpandClickListener.onClick(this);
+ }
+
/**
* Returns the number of channels covered by the notification row (including its children if
* it's a summary notification).
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 f8d9c46..7a6109d 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
@@ -130,7 +130,13 @@
mView.setOnDismissRunnable(mOnDismissRunnable);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
- mView.setLongPressListener(mNotificationGutsManager::openGuts);
+ mView.setLongPressListener((v, x, y, item) -> {
+ if (mView.isSummaryWithChildren()) {
+ mView.expandNotification();
+ return true;
+ }
+ return mNotificationGutsManager.openGuts(v, x, y, item);
+ });
}
if (ENABLE_REMOTE_INPUT) {
mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 5797944..0831c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -767,6 +767,10 @@
return mContentTranslation;
}
+ public boolean wantsAddAndRemoveAnimations() {
+ return true;
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 0ccebc13..56f8e08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -109,7 +109,7 @@
}
@Nullable
- private CharSequence resolveText(Notification notification) {
+ public static CharSequence resolveText(Notification notification) {
CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
if (contentText == null) {
contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
@@ -118,7 +118,7 @@
}
@Nullable
- private CharSequence resolveTitle(Notification notification) {
+ public static CharSequence resolveTitle(Notification notification) {
CharSequence titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
if (titleText == null) {
titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
index e4e3ebc..3ee2673 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
@@ -115,6 +115,9 @@
mLogger.logManagedRow(entry.getKey());
final BindEntry bindEntry = getBindEntry(entry);
+ if (bindEntry == null) {
+ return;
+ }
bindEntry.row = row;
if (bindEntry.invalidated) {
requestPipelineRun(entry);
@@ -223,11 +226,6 @@
private @NonNull BindEntry getBindEntry(NotificationEntry entry) {
final BindEntry bindEntry = mBindEntries.get(entry);
- if (bindEntry == null) {
- throw new IllegalStateException(
- String.format("Attempting bind on an inactive notification. key: %s",
- entry.getKey()));
- }
return bindEntry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index cc5de65..66c07bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -135,10 +135,13 @@
}
private void bindActions() {
+ final OnClickListener settingsOnClickListener = getSettingsOnClickListener();
final View settingsButton = findViewById(R.id.info);
- settingsButton.setOnClickListener(getSettingsOnClickListener());
+ settingsButton.setOnClickListener(settingsOnClickListener);
settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
+ findViewById(R.id.settings_link).setOnClickListener(settingsOnClickListener);
+
TextView msg = findViewById(R.id.non_configurable_text);
msg.setText(getResources().getString(R.string.no_shortcut, mAppName));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index b96cff8..93d3f3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -178,38 +178,6 @@
final MediaSession.Token token = mRow.getEntry().getSbn().getNotification().extras
.getParcelable(Notification.EXTRA_MEDIA_SESSION);
- if (Utils.useQsMediaPlayer(mContext) && token != null) {
- final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras
- .getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
- int tintColor = getNotificationHeader().getOriginalIconColor();
- NotificationShadeWindowController ctrl = Dependency.get(
- NotificationShadeWindowController.class);
- QuickQSPanel panel = ctrl.getNotificationShadeView().findViewById(
- com.android.systemui.R.id.quick_qs_panel);
- StatusBarNotification sbn = mRow.getEntry().getSbn();
- Notification notif = sbn.getNotification();
- Drawable iconDrawable = notif.getSmallIcon().loadDrawable(mContext);
- panel.getMediaPlayer().setMediaSession(token,
- iconDrawable,
- notif.getLargeIcon(),
- tintColor,
- mBackgroundColor,
- mActions,
- compactActions,
- notif.contentIntent,
- sbn.getKey());
- QSPanel bigPanel = ctrl.getNotificationShadeView().findViewById(
- com.android.systemui.R.id.quick_settings_panel);
- bigPanel.addMediaSession(token,
- iconDrawable,
- notif.getLargeIcon(),
- tintColor,
- mBackgroundColor,
- mActions,
- sbn,
- sbn.getKey());
- }
-
boolean showCompactSeekbar = mMediaManager.getShowCompactMediaSeekbar();
if (token == null || (COMPACT_MEDIA_TAG.equals(mView.getTag()) && !showCompactSeekbar)) {
if (mSeekBarView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java
index ab055e1..3ac322f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -37,7 +38,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mContentView = findViewById(R.id.keyguard_media_view);
}
@Override
@@ -52,4 +52,17 @@
public void setBackgroundColor(int color) {
setTintColor(color);
}
+
+ public void setContentView(ViewGroup contentView) {
+ mContentView = contentView;
+ addView(contentView);
+ ViewGroup.LayoutParams layoutParams = contentView.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ }
+
+ @Override
+ public boolean wantsAddAndRemoveAnimations() {
+ return false;
+ }
}
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 c9b1318..99691b7 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
@@ -463,7 +463,8 @@
mAttachedChildren.add(i, desiredChild);
result = true;
} else {
- visualStabilityManager.addReorderingAllowedCallback(callback);
+ visualStabilityManager.addReorderingAllowedCallback(callback,
+ false /* persistent */);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 9d456ef..bad36bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -32,8 +32,8 @@
* Represents the bounds of a section of the notification shade and handles animation when the
* bounds change.
*/
-class NotificationSection {
- private @NotificationSectionsManager.PriorityBucket int mBucket;
+public class NotificationSection {
+ private @PriorityBucket int mBucket;
private View mOwningView;
private Rect mBounds = new Rect();
private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
@@ -44,7 +44,7 @@
private ActivatableNotificationView mFirstVisibleChild;
private ActivatableNotificationView mLastVisibleChild;
- NotificationSection(View owningView, @NotificationSectionsManager.PriorityBucket int bucket) {
+ NotificationSection(View owningView, @PriorityBucket int bucket) {
mOwningView = owningView;
mBucket = bucket;
}
@@ -74,7 +74,7 @@
return mBottomAnimator != null || mTopAnimator != null;
}
- @NotificationSectionsManager.PriorityBucket
+ @PriorityBucket
public int getBucket() {
return mBucket;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
new file mode 100644
index 0000000..17b4143
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
@@ -0,0 +1,93 @@
+/*
+ * 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 com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationSectionLog
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private const val TAG = "NotifSections"
+
+@Singleton
+class NotificationSectionsLogger @Inject constructor(
+ @NotificationSectionLog private val logBuffer: LogBuffer
+) {
+
+ fun logStartSectionUpdate(reason: String) = logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = reason },
+ { "Updating section boundaries: $reason" }
+ )
+
+ fun logIncomingHeader(position: Int) = logPosition(position, "INCOMING HEADER")
+ fun logMediaControls(position: Int) = logPosition(position, "MEDIA CONTROLS")
+ fun logConversationsHeader(position: Int) = logPosition(position, "CONVERSATIONS HEADER")
+ fun logAlertingHeader(position: Int) = logPosition(position, "ALERTING HEADER")
+ fun logSilentHeader(position: Int) = logPosition(position, "SILENT HEADER")
+
+ fun logOther(position: Int, clazz: Class<*>) = logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = position
+ str1 = clazz.name
+ },
+ { "$int1: other ($str1)" }
+ )
+
+ fun logHeadsUp(position: Int, isHeadsUp: Boolean) =
+ logPosition(position, "Heads Up", isHeadsUp)
+ fun logConversation(position: Int, isHeadsUp: Boolean) =
+ logPosition(position, "Conversation", isHeadsUp)
+ fun logAlerting(position: Int, isHeadsUp: Boolean) =
+ logPosition(position, "Alerting", isHeadsUp)
+ fun logSilent(position: Int, isHeadsUp: Boolean) =
+ logPosition(position, "Silent", isHeadsUp)
+ fun logForegroundService(position: Int, isHeadsUp: Boolean) =
+ logPosition(position, "Foreground Service", isHeadsUp)
+
+ fun logStr(str: String) = logBuffer.log(TAG, LogLevel.DEBUG, { str1 = str }, { "$str1" })
+
+ private fun logPosition(position: Int, label: String, isHeadsUp: Boolean) {
+ val headsUpTag = if (isHeadsUp) " (HUN)" else ""
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = position
+ str1 = label
+ str2 = headsUpTag
+ },
+ {
+ "$int1: $str1$str2"
+ }
+ )
+ }
+
+ private fun logPosition(position: Int, label: String) = logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = position
+ str1 = label
+ },
+ { "$int1: $str1" }
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
deleted file mode 100644
index d02037c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ /dev/null
@@ -1,583 +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.stack;
-
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.ColorInt;
-import android.annotation.IntDef;
-import android.annotation.LayoutRes;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.provider.Settings;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.KeyguardMediaPlayer;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.people.DataListener;
-import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
-import com.android.systemui.statusbar.notification.people.PeopleHubViewBoundary;
-import com.android.systemui.statusbar.notification.people.PersonViewModel;
-import com.android.systemui.statusbar.notification.people.Subscription;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-
-import java.lang.annotation.Retention;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-import kotlin.sequences.Sequence;
-
-/**
- * Manages the boundaries of the two notification sections (high priority and low priority). Also
- * shows/hides the headers for those sections where appropriate.
- *
- * TODO: Move remaining sections logic from NSSL into this class.
- */
-public class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvider {
-
- private static final String TAG = "NotifSectionsManager";
- private static final boolean DEBUG = false;
- private static final boolean ENABLE_SNOOZED_CONVERSATION_HUB = false;
-
- private final ActivityStarter mActivityStarter;
- private final StatusBarStateController mStatusBarStateController;
- private final ConfigurationController mConfigurationController;
- private final PeopleHubViewAdapter mPeopleHubViewAdapter;
- private final KeyguardMediaPlayer mKeyguardMediaPlayer;
- private final NotificationSectionsFeatureManager mSectionsFeatureManager;
- private final int mNumberOfSections;
-
- private final PeopleHubViewBoundary mPeopleHubViewBoundary = new PeopleHubViewBoundary() {
- @Override
- public void setVisible(boolean isVisible) {
- if (mPeopleHubVisible != isVisible) {
- mPeopleHubVisible = isVisible;
- if (mInitialized) {
- updateSectionBoundaries();
- }
- }
- }
-
- @NonNull
- @Override
- public View getAssociatedViewForClickAnimation() {
- return mPeopleHubView;
- }
-
- @NonNull
- @Override
- public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() {
- return mPeopleHubView.getPersonViewAdapters();
- }
- };
-
- private NotificationStackScrollLayout mParent;
- private boolean mInitialized = false;
-
- private SectionHeaderView mGentleHeader;
- @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
-
- private SectionHeaderView mAlertingHeader;
-
- private PeopleHubView mPeopleHubView;
- private boolean mPeopleHubVisible = false;
- @Nullable private Subscription mPeopleHubSubscription;
-
- private MediaHeaderView mMediaControlsView;
-
- @Inject
- NotificationSectionsManager(
- ActivityStarter activityStarter,
- StatusBarStateController statusBarStateController,
- ConfigurationController configurationController,
- PeopleHubViewAdapter peopleHubViewAdapter,
- KeyguardMediaPlayer keyguardMediaPlayer,
- NotificationSectionsFeatureManager sectionsFeatureManager) {
- mActivityStarter = activityStarter;
- mStatusBarStateController = statusBarStateController;
- mConfigurationController = configurationController;
- mPeopleHubViewAdapter = peopleHubViewAdapter;
- mKeyguardMediaPlayer = keyguardMediaPlayer;
- mSectionsFeatureManager = sectionsFeatureManager;
- mNumberOfSections = mSectionsFeatureManager.getNumberOfBuckets();
- }
-
- NotificationSection[] createSectionsForBuckets() {
- int[] buckets = mSectionsFeatureManager.getNotificationBuckets();
- NotificationSection[] sections = new NotificationSection[buckets.length];
- for (int i = 0; i < buckets.length; i++) {
- sections[i] = new NotificationSection(mParent, buckets[i] /* bucket */);
- }
-
- return sections;
- }
-
- /** Must be called before use. */
- void initialize(
- NotificationStackScrollLayout parent, LayoutInflater layoutInflater) {
- if (mInitialized) {
- throw new IllegalStateException("NotificationSectionsManager already initialized");
- }
- mInitialized = true;
- mParent = parent;
- reinflateViews(layoutInflater);
- mConfigurationController.addCallback(mConfigurationListener);
- }
-
- private <T extends ExpandableView> T reinflateView(
- T view, LayoutInflater layoutInflater, @LayoutRes int layoutResId) {
- int oldPos = -1;
- if (view != null) {
- if (view.getTransientContainer() != null) {
- view.getTransientContainer().removeView(mGentleHeader);
- } else if (view.getParent() != null) {
- oldPos = mParent.indexOfChild(view);
- mParent.removeView(view);
- }
- }
-
- view = (T) layoutInflater.inflate(layoutResId, mParent, false);
-
- if (oldPos != -1) {
- mParent.addView(view, oldPos);
- }
-
- return view;
- }
-
- /**
- * Reinflates the entire notification header, including all decoration views.
- */
- void reinflateViews(LayoutInflater layoutInflater) {
- mGentleHeader = reinflateView(
- mGentleHeader, layoutInflater, R.layout.status_bar_notification_section_header);
- mGentleHeader.setHeaderText(R.string.notification_section_header_gentle);
- mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
- mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick);
-
- mAlertingHeader = reinflateView(
- mAlertingHeader, layoutInflater, R.layout.status_bar_notification_section_header);
- mAlertingHeader.setHeaderText(R.string.notification_section_header_alerting);
- mAlertingHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
-
- if (mPeopleHubSubscription != null) {
- mPeopleHubSubscription.unsubscribe();
- }
- mPeopleHubView = reinflateView(mPeopleHubView, layoutInflater, R.layout.people_strip);
- if (ENABLE_SNOOZED_CONVERSATION_HUB) {
- mPeopleHubSubscription = mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
- }
-
- if (mMediaControlsView != null) {
- mKeyguardMediaPlayer.unbindView();
- }
- mMediaControlsView = reinflateView(mMediaControlsView, layoutInflater,
- R.layout.keyguard_media_header);
- mKeyguardMediaPlayer.bindView(mMediaControlsView);
- }
-
- /** Listener for when the "clear all" button is clicked on the gentle notification header. */
- void setOnClearGentleNotifsClickListener(View.OnClickListener listener) {
- mOnClearGentleNotifsClickListener = listener;
- }
-
- @Override
- public boolean beginsSection(@NonNull View view, @Nullable View previous) {
- return view == mGentleHeader
- || view == mMediaControlsView
- || view == mPeopleHubView
- || view == mAlertingHeader
- || !Objects.equals(getBucket(view), getBucket(previous));
- }
-
- private boolean isUsingMultipleSections() {
- return mNumberOfSections > 1;
- }
-
- @Nullable
- private Integer getBucket(View view) {
- if (view == mGentleHeader) {
- return BUCKET_SILENT;
- } else if (view == mMediaControlsView) {
- return BUCKET_MEDIA_CONTROLS;
- } else if (view == mPeopleHubView) {
- return BUCKET_PEOPLE;
- } else if (view == mAlertingHeader) {
- return BUCKET_ALERTING;
- } else if (view instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) view).getEntry().getBucket();
- }
- return null;
- }
-
- /**
- * Should be called whenever notifs are added, removed, or updated. Updates section boundary
- * bookkeeping and adds/moves/removes section headers if appropriate.
- */
- void updateSectionBoundaries() {
- if (!isUsingMultipleSections()) {
- return;
- }
-
- // The overall strategy here is to iterate over the current children of mParent, looking
- // for where the sections headers are currently positioned, and where each section begins.
- // Then, once we find the start of a new section, we track that position as the "target" for
- // the section header, adjusted for the case where existing headers are in front of that
- // target, but won't be once they are moved / removed after the pass has completed.
-
- final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
- final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled();
- final boolean isKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
- final boolean usingMediaControls = mSectionsFeatureManager.isMediaControlsEnabled();
-
- boolean peopleNotifsPresent = false;
-
- int currentMediaControlsIdx = -1;
- // Currently, just putting media controls in the front and incrementing the position based
- // on the number of heads-up notifs.
- int mediaControlsTarget = isKeyguard && usingMediaControls ? 0 : -1;
- int currentPeopleHeaderIdx = -1;
- int peopleHeaderTarget = -1;
- int currentAlertingHeaderIdx = -1;
- int alertingHeaderTarget = -1;
- int currentGentleHeaderIdx = -1;
- int gentleHeaderTarget = -1;
-
- int lastNotifIndex = 0;
-
- final int childCount = mParent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mParent.getChildAt(i);
-
- // Track the existing positions of the headers
- if (child == mMediaControlsView) {
- currentMediaControlsIdx = i;
- continue;
- }
- if (child == mPeopleHubView) {
- currentPeopleHeaderIdx = i;
- continue;
- }
- if (child == mAlertingHeader) {
- currentAlertingHeaderIdx = i;
- continue;
- }
- if (child == mGentleHeader) {
- currentGentleHeaderIdx = i;
- continue;
- }
-
- if (!(child instanceof ExpandableNotificationRow)) {
- continue;
- }
- lastNotifIndex = i;
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- // Once we enter a new section, calculate the target position for the header.
- switch (row.getEntry().getBucket()) {
- case BUCKET_HEADS_UP:
- if (mediaControlsTarget != -1) {
- mediaControlsTarget++;
- }
- break;
- case BUCKET_PEOPLE:
- peopleNotifsPresent = true;
- if (showHeaders && peopleHeaderTarget == -1) {
- peopleHeaderTarget = i;
- // Offset the target if there are other headers before this that will be
- // moved.
- if (currentPeopleHeaderIdx != -1) {
- peopleHeaderTarget--;
- }
- if (currentAlertingHeaderIdx != -1) {
- peopleHeaderTarget--;
- }
- if (currentGentleHeaderIdx != -1) {
- peopleHeaderTarget--;
- }
- }
- break;
- case BUCKET_ALERTING:
- if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) {
- alertingHeaderTarget = i;
- // Offset the target if there are other headers before this that will be
- // moved.
- if (currentAlertingHeaderIdx != -1) {
- alertingHeaderTarget--;
- }
- if (currentGentleHeaderIdx != -1) {
- alertingHeaderTarget--;
- }
- }
- break;
- case BUCKET_SILENT:
- if (showHeaders && gentleHeaderTarget == -1) {
- gentleHeaderTarget = i;
- // Offset the target if there are other headers before this that will be
- // moved.
- if (currentGentleHeaderIdx != -1) {
- gentleHeaderTarget--;
- }
- }
- break;
- default:
- throw new IllegalStateException("Cannot find section bucket for view");
- }
- }
- if (showHeaders && usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
- // Insert the people header even if there are no people visible, in order to show
- // the hub. Put it directly above the next header.
- if (alertingHeaderTarget != -1) {
- peopleHeaderTarget = alertingHeaderTarget;
- } else if (gentleHeaderTarget != -1) {
- peopleHeaderTarget = gentleHeaderTarget;
- } else {
- // Put it at the end of the list.
- peopleHeaderTarget = lastNotifIndex;
- }
- // Offset the target to account for the current position of the people header.
- if (currentPeopleHeaderIdx != -1 && currentPeopleHeaderIdx < peopleHeaderTarget) {
- peopleHeaderTarget--;
- }
- }
-
- // Add headers in reverse order to preserve indices
- adjustHeaderVisibilityAndPosition(
- gentleHeaderTarget, mGentleHeader, currentGentleHeaderIdx);
- adjustHeaderVisibilityAndPosition(
- alertingHeaderTarget, mAlertingHeader, currentAlertingHeaderIdx);
- adjustHeaderVisibilityAndPosition(
- peopleHeaderTarget, mPeopleHubView, currentPeopleHeaderIdx);
- adjustViewPosition(
- mediaControlsTarget, mMediaControlsView, currentMediaControlsIdx);
-
- // Update headers to reflect state of section contents
- mGentleHeader.setAreThereDismissableGentleNotifs(
- mParent.hasActiveClearableNotifications(ROWS_GENTLE));
- mPeopleHubView.setCanSwipe(showHeaders && mPeopleHubVisible && !peopleNotifsPresent);
- if (peopleHeaderTarget != currentPeopleHeaderIdx) {
- mPeopleHubView.resetTranslation();
- }
- }
-
- private void adjustHeaderVisibilityAndPosition(
- int targetPosition, StackScrollerDecorView header, int currentPosition) {
- if (targetPosition == -1) {
- if (currentPosition != -1) {
- mParent.removeView(header);
- }
- } else {
- if (currentPosition == -1) {
- // If the header is animating away, it will still have a parent, so detach it first
- // TODO: We should really cancel the active animations here. This will happen
- // automatically when the view's intro animation starts, but it's a fragile link.
- if (header.getTransientContainer() != null) {
- header.getTransientContainer().removeTransientView(header);
- header.setTransientContainer(null);
- }
- header.setContentVisible(true);
- mParent.addView(header, targetPosition);
- } else {
- mParent.changeViewPosition(header, targetPosition);
- }
- }
- }
-
- private void adjustViewPosition(int targetPosition, ExpandableView header,
- int currentPosition) {
- if (targetPosition == -1) {
- if (currentPosition != -1) {
- mParent.removeView(header);
- }
- } else {
- if (currentPosition == -1) {
- // If the header is animating away, it will still have a parent, so detach it first
- // TODO: We should really cancel the active animations here. This will happen
- // automatically when the view's intro animation starts, but it's a fragile link.
- if (header.getTransientContainer() != null) {
- header.getTransientContainer().removeTransientView(header);
- header.setTransientContainer(null);
- }
- mParent.addView(header, targetPosition);
- } else {
- mParent.changeViewPosition(header, targetPosition);
- }
- }
- }
-
- /**
- * Updates the boundaries (as tracked by their first and last views) of the priority sections.
- *
- * @return {@code true} If the last view in the top section changed (so we need to animate).
- */
- boolean updateFirstAndLastViewsForAllSections(
- NotificationSection[] sections,
- List<ActivatableNotificationView> children) {
-
- if (sections.length <= 0 || children.size() <= 0) {
- for (NotificationSection s : sections) {
- s.setFirstVisibleChild(null);
- s.setLastVisibleChild(null);
- }
- return false;
- }
-
- boolean changed = false;
- ArrayList<ActivatableNotificationView> viewsInBucket = new ArrayList<>();
- for (NotificationSection s : sections) {
- int filter = s.getBucket();
- viewsInBucket.clear();
-
- //TODO: do this in a single pass, and more better
- for (ActivatableNotificationView v : children) {
- Integer bucket = getBucket(v);
- if (bucket == null) {
- throw new IllegalArgumentException("Cannot find section bucket for view");
- }
-
- if (bucket == filter) {
- viewsInBucket.add(v);
- }
-
- if (viewsInBucket.size() >= 1) {
- changed |= s.setFirstVisibleChild(viewsInBucket.get(0));
- changed |= s.setLastVisibleChild(viewsInBucket.get(viewsInBucket.size() - 1));
- } else {
- changed |= s.setFirstVisibleChild(null);
- changed |= s.setLastVisibleChild(null);
- }
- }
- }
-
- if (DEBUG) {
- logSections(sections);
- }
-
- return changed;
- }
-
- private void logSections(NotificationSection[] sections) {
- for (int i = 0; i < sections.length; i++) {
- NotificationSection s = sections[i];
- ActivatableNotificationView first = s.getFirstVisibleChild();
- String fs = first == null ? "(null)"
- : (first instanceof ExpandableNotificationRow)
- ? ((ExpandableNotificationRow) first).getEntry().getKey()
- : Integer.toHexString(System.identityHashCode(first));
- ActivatableNotificationView last = s.getLastVisibleChild();
- String ls = last == null ? "(null)"
- : (last instanceof ExpandableNotificationRow)
- ? ((ExpandableNotificationRow) last).getEntry().getKey()
- : Integer.toHexString(System.identityHashCode(last));
- android.util.Log.d(TAG, "updateSections: f=" + fs + " s=" + i);
- android.util.Log.d(TAG, "updateSections: l=" + ls + " s=" + i);
- }
- }
-
- @VisibleForTesting
- ExpandableView getGentleHeaderView() {
- return mGentleHeader;
- }
-
- @VisibleForTesting
- ExpandableView getAlertingHeaderView() {
- return mAlertingHeader;
- }
-
- @VisibleForTesting
- ExpandableView getPeopleHeaderView() {
- return mPeopleHubView;
- }
-
- @VisibleForTesting
- ExpandableView getMediaControlsView() {
- return mMediaControlsView;
- }
-
- @VisibleForTesting
- void setPeopleHubVisible(boolean visible) {
- mPeopleHubVisible = visible;
- }
-
- private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
- @Override
- public void onLocaleListChanged() {
- reinflateViews(LayoutInflater.from(mParent.getContext()));
- }
- };
-
- private void onGentleHeaderClick(View v) {
- Intent intent = new Intent(Settings.ACTION_NOTIFICATION_SETTINGS);
- mActivityStarter.startActivity(
- intent,
- true,
- true,
- Intent.FLAG_ACTIVITY_SINGLE_TOP);
- }
-
- private void onClearGentleNotifsClick(View v) {
- if (mOnClearGentleNotifsClickListener != null) {
- mOnClearGentleNotifsClickListener.onClick(v);
- }
- }
-
- void hidePeopleRow() {
- mPeopleHubVisible = false;
- updateSectionBoundaries();
- }
-
- void setHeaderForegroundColor(@ColorInt int color) {
- mPeopleHubView.setTextColor(color);
- mGentleHeader.setForegroundColor(color);
- mAlertingHeader.setForegroundColor(color);
- }
-
- /**
- * For now, declare the available notification buckets (sections) here so that other
- * presentation code can decide what to do based on an entry's buckets
- */
- @Retention(SOURCE)
- @IntDef(prefix = { "BUCKET_" }, value = {
- BUCKET_HEADS_UP,
- BUCKET_MEDIA_CONTROLS,
- BUCKET_PEOPLE,
- BUCKET_ALERTING,
- BUCKET_SILENT
- })
- public @interface PriorityBucket {}
- public static final int BUCKET_HEADS_UP = 0;
- public static final int BUCKET_MEDIA_CONTROLS = 1;
- public static final int BUCKET_PEOPLE = 2;
- public static final int BUCKET_ALERTING = 3;
- public static final int BUCKET_SILENT = 4;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
new file mode 100644
index 0000000..e39a4a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -0,0 +1,595 @@
+/*
+ * 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.stack
+
+import android.annotation.ColorInt
+import android.annotation.IntDef
+import android.annotation.LayoutRes
+import android.content.Intent
+import android.provider.Settings
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.R
+import com.android.systemui.media.KeyguardMediaController
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.people.DataListener
+import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter
+import com.android.systemui.statusbar.notification.people.PeopleHubViewBoundary
+import com.android.systemui.statusbar.notification.people.PersonViewModel
+import com.android.systemui.statusbar.notification.people.Subscription
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.children
+import com.android.systemui.util.foldToSparseArray
+import javax.inject.Inject
+
+/**
+ * Manages the boundaries of the two notification sections (high priority and low priority). Also
+ * shows/hides the headers for those sections where appropriate.
+ *
+ * TODO: Move remaining sections logic from NSSL into this class.
+ */
+class NotificationSectionsManager @Inject internal constructor(
+ private val activityStarter: ActivityStarter,
+ private val statusBarStateController: StatusBarStateController,
+ private val configurationController: ConfigurationController,
+ private val peopleHubViewAdapter: PeopleHubViewAdapter,
+ private val keyguardMediaController: KeyguardMediaController,
+ private val sectionsFeatureManager: NotificationSectionsFeatureManager,
+ private val logger: NotificationSectionsLogger
+) : SectionProvider {
+
+ private val configurationListener = object : ConfigurationController.ConfigurationListener {
+ override fun onLocaleListChanged() {
+ reinflateViews(LayoutInflater.from(parent.context))
+ }
+ }
+
+ private val peopleHubViewBoundary: PeopleHubViewBoundary = object : PeopleHubViewBoundary {
+ override fun setVisible(isVisible: Boolean) {
+ if (peopleHubVisible != isVisible) {
+ peopleHubVisible = isVisible
+ if (initialized) {
+ updateSectionBoundaries("PeopleHub visibility changed")
+ }
+ }
+ }
+
+ override val associatedViewForClickAnimation: View
+ get() = peopleHeaderView!!
+
+ override val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
+ get() = peopleHeaderView!!.personViewAdapters
+ }
+
+ private lateinit var parent: NotificationStackScrollLayout
+ private var initialized = false
+ private var onClearSilentNotifsClickListener: View.OnClickListener? = null
+
+ @get:VisibleForTesting
+ var silentHeaderView: SectionHeaderView? = null
+ private set
+
+ @get:VisibleForTesting
+ var alertingHeaderView: SectionHeaderView? = null
+ private set
+
+ @get:VisibleForTesting
+ var incomingHeaderView: SectionHeaderView? = null
+ private set
+
+ @get:VisibleForTesting
+ var peopleHeaderView: PeopleHubView? = null
+ private set
+
+ @set:VisibleForTesting
+ var peopleHubVisible = false
+ private var peopleHubSubscription: Subscription? = null
+
+ @get:VisibleForTesting
+ var mediaControlsView: MediaHeaderView? = null
+ private set
+
+ /** Must be called before use. */
+ fun initialize(parent: NotificationStackScrollLayout, layoutInflater: LayoutInflater) {
+ check(!initialized) { "NotificationSectionsManager already initialized" }
+ initialized = true
+ this.parent = parent
+ reinflateViews(layoutInflater)
+ configurationController.addCallback(configurationListener)
+ }
+
+ private fun <T : ExpandableView> reinflateView(
+ view: T?,
+ layoutInflater: LayoutInflater,
+ @LayoutRes layoutResId: Int
+ ): T {
+ var oldPos = -1
+ view?.let {
+ view.transientContainer?.removeView(view)
+ if (view.parent === parent) {
+ oldPos = parent.indexOfChild(view)
+ parent.removeView(view)
+ }
+ }
+ val inflated = layoutInflater.inflate(layoutResId, parent, false) as T
+ if (oldPos != -1) {
+ parent.addView(inflated, oldPos)
+ }
+ return inflated
+ }
+
+ fun createSectionsForBuckets(): Array<NotificationSection> =
+ sectionsFeatureManager.getNotificationBuckets()
+ .map { NotificationSection(parent, it) }
+ .toTypedArray()
+
+ /**
+ * Reinflates the entire notification header, including all decoration views.
+ */
+ fun reinflateViews(layoutInflater: LayoutInflater) {
+ silentHeaderView = reinflateView(
+ silentHeaderView, layoutInflater, R.layout.status_bar_notification_section_header
+ ).apply {
+ setHeaderText(R.string.notification_section_header_gentle)
+ setOnHeaderClickListener { onGentleHeaderClick() }
+ setOnClearAllClickListener { onClearGentleNotifsClick(it) }
+ }
+ alertingHeaderView = reinflateView(
+ alertingHeaderView, layoutInflater, R.layout.status_bar_notification_section_header
+ ).apply {
+ setHeaderText(R.string.notification_section_header_alerting)
+ setOnHeaderClickListener { onGentleHeaderClick() }
+ }
+ peopleHubSubscription?.unsubscribe()
+ peopleHubSubscription = null
+ peopleHeaderView = reinflateView(peopleHeaderView, layoutInflater, R.layout.people_strip)
+ if (ENABLE_SNOOZED_CONVERSATION_HUB) {
+ peopleHubSubscription = peopleHubViewAdapter.bindView(peopleHubViewBoundary)
+ }
+ incomingHeaderView = reinflateView(
+ incomingHeaderView, layoutInflater, R.layout.status_bar_notification_section_header
+ ).apply {
+ setHeaderText(R.string.notification_section_header_incoming)
+ setOnHeaderClickListener { onGentleHeaderClick() }
+ }
+ mediaControlsView =
+ reinflateView(mediaControlsView, layoutInflater, R.layout.keyguard_media_header)
+ .also(keyguardMediaController::attach)
+ }
+
+ override fun beginsSection(view: View, previous: View?): Boolean =
+ view === silentHeaderView ||
+ view === mediaControlsView ||
+ view === peopleHeaderView ||
+ view === alertingHeaderView ||
+ view === incomingHeaderView ||
+ getBucket(view) != getBucket(previous)
+
+ private fun getBucket(view: View?): Int? = when {
+ view === silentHeaderView -> BUCKET_SILENT
+ view === incomingHeaderView -> BUCKET_HEADS_UP
+ view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
+ view === peopleHeaderView -> BUCKET_PEOPLE
+ view === alertingHeaderView -> BUCKET_ALERTING
+ view is ExpandableNotificationRow -> view.entry.bucket
+ else -> null
+ }
+
+ private fun logShadeContents() = parent.children.forEachIndexed { i, child ->
+ when {
+ child === incomingHeaderView -> logger.logIncomingHeader(i)
+ child === mediaControlsView -> logger.logMediaControls(i)
+ child === peopleHeaderView -> logger.logConversationsHeader(i)
+ child === alertingHeaderView -> logger.logAlertingHeader(i)
+ child === silentHeaderView -> logger.logSilentHeader(i)
+ child !is ExpandableNotificationRow -> logger.logOther(i, child.javaClass)
+ else -> {
+ val isHeadsUp = child.isHeadsUp
+ when (child.entry.bucket) {
+ BUCKET_HEADS_UP -> logger.logHeadsUp(i, isHeadsUp)
+ BUCKET_PEOPLE -> logger.logConversation(i, isHeadsUp)
+ BUCKET_ALERTING -> logger.logAlerting(i, isHeadsUp)
+ BUCKET_SILENT -> logger.logSilent(i, isHeadsUp)
+ }
+ }
+ }
+ }
+
+ private val isUsingMultipleSections: Boolean
+ get() = sectionsFeatureManager.getNumberOfBuckets() > 1
+
+ @VisibleForTesting
+ fun updateSectionBoundaries() = updateSectionBoundaries("test")
+
+ /**
+ * Should be called whenever notifs are added, removed, or updated. Updates section boundary
+ * bookkeeping and adds/moves/removes section headers if appropriate.
+ */
+ fun updateSectionBoundaries(reason: String) {
+ if (!isUsingMultipleSections) {
+ return
+ }
+ logger.logStartSectionUpdate(reason)
+
+ // The overall strategy here is to iterate over the current children of mParent, looking
+ // for where the sections headers are currently positioned, and where each section begins.
+ // Then, once we find the start of a new section, we track that position as the "target" for
+ // the section header, adjusted for the case where existing headers are in front of that
+ // target, but won't be once they are moved / removed after the pass has completed.
+ val showHeaders = statusBarStateController.state != StatusBarState.KEYGUARD
+ val usingPeopleFiltering = sectionsFeatureManager.isFilteringEnabled()
+ val usingMediaControls = sectionsFeatureManager.isMediaControlsEnabled()
+
+ var peopleNotifsPresent = false
+ var currentMediaControlsIdx = -1
+ val mediaControlsTarget = if (usingMediaControls) 0 else -1
+ var currentIncomingHeaderIdx = -1
+ var incomingHeaderTarget = -1
+ var currentPeopleHeaderIdx = -1
+ var peopleHeaderTarget = -1
+ var currentAlertingHeaderIdx = -1
+ var alertingHeaderTarget = -1
+ var currentGentleHeaderIdx = -1
+ var gentleHeaderTarget = -1
+
+ var lastNotifIndex = 0
+ var lastIncomingIndex = -1
+ var prev: ExpandableNotificationRow? = null
+
+ for ((i, child) in parent.children.withIndex()) {
+ when {
+ // Track the existing positions of the headers
+ child === incomingHeaderView -> {
+ logger.logIncomingHeader(i)
+ currentIncomingHeaderIdx = i
+ }
+ child === mediaControlsView -> {
+ logger.logMediaControls(i)
+ currentMediaControlsIdx = i
+ }
+ child === peopleHeaderView -> {
+ logger.logConversationsHeader(i)
+ currentPeopleHeaderIdx = i
+ }
+ child === alertingHeaderView -> {
+ logger.logAlertingHeader(i)
+ currentAlertingHeaderIdx = i
+ }
+ child === silentHeaderView -> {
+ logger.logSilentHeader(i)
+ currentGentleHeaderIdx = i
+ }
+ child !is ExpandableNotificationRow -> logger.logOther(i, child.javaClass)
+ else -> {
+ lastNotifIndex = i
+ // Is there a section discontinuity? This usually occurs due to HUNs
+ if (prev?.entry?.bucket?.let { it > child.entry.bucket } == true) {
+ // Remove existing headers, and move the Incoming header if necessary
+ if (alertingHeaderTarget != -1) {
+ if (showHeaders && incomingHeaderTarget != -1) {
+ incomingHeaderTarget = alertingHeaderTarget
+ }
+ alertingHeaderTarget = -1
+ }
+ if (peopleHeaderTarget != -1) {
+ if (showHeaders && incomingHeaderTarget != -1) {
+ incomingHeaderTarget = peopleHeaderTarget
+ }
+ peopleHeaderTarget = -1
+ }
+ if (showHeaders && incomingHeaderTarget == -1) {
+ incomingHeaderTarget = 0
+ }
+ // Walk backwards changing all previous notifications to the Incoming
+ // section
+ for (j in i - 1 downTo lastIncomingIndex + 1) {
+ val prevChild = parent.getChildAt(j)
+ if (prevChild is ExpandableNotificationRow) {
+ prevChild.entry.bucket = BUCKET_HEADS_UP
+ }
+ }
+ // Track the new bottom of the Incoming section
+ lastIncomingIndex = i - 1
+ }
+ val isHeadsUp = child.isHeadsUp
+ when (child.entry.bucket) {
+ BUCKET_FOREGROUND_SERVICE -> logger.logForegroundService(i, isHeadsUp)
+ BUCKET_PEOPLE -> {
+ logger.logConversation(i, isHeadsUp)
+ peopleNotifsPresent = true
+ if (showHeaders && peopleHeaderTarget == -1) {
+ peopleHeaderTarget = i
+ // Offset the target if there are other headers before this that
+ // will be moved.
+ if (currentPeopleHeaderIdx != -1) {
+ peopleHeaderTarget--
+ }
+ if (currentAlertingHeaderIdx != -1) {
+ peopleHeaderTarget--
+ }
+ if (currentGentleHeaderIdx != -1) {
+ peopleHeaderTarget--
+ }
+ }
+ }
+ BUCKET_ALERTING -> {
+ logger.logAlerting(i, isHeadsUp)
+ if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) {
+ alertingHeaderTarget = i
+ // Offset the target if there are other headers before this that
+ // will be moved.
+ if (currentAlertingHeaderIdx != -1) {
+ alertingHeaderTarget--
+ }
+ if (currentGentleHeaderIdx != -1) {
+ alertingHeaderTarget--
+ }
+ }
+ }
+ BUCKET_SILENT -> {
+ logger.logSilent(i, isHeadsUp)
+ if (showHeaders && gentleHeaderTarget == -1) {
+ gentleHeaderTarget = i
+ // Offset the target if there are other headers before this that
+ // will be moved.
+ if (currentGentleHeaderIdx != -1) {
+ gentleHeaderTarget--
+ }
+ }
+ }
+ }
+
+ prev = child
+ }
+ }
+ }
+
+ if (showHeaders && usingPeopleFiltering && peopleHubVisible && peopleHeaderTarget == -1) {
+ // Insert the people header even if there are no people visible, in order to show
+ // the hub. Put it directly above the next header.
+ peopleHeaderTarget = when {
+ alertingHeaderTarget != -1 -> alertingHeaderTarget
+ gentleHeaderTarget != -1 -> gentleHeaderTarget
+ else -> lastNotifIndex // Put it at the end of the list.
+ }
+ // Offset the target to account for the current position of the people header.
+ if (currentPeopleHeaderIdx != -1 && currentPeopleHeaderIdx < peopleHeaderTarget) {
+ peopleHeaderTarget--
+ }
+ }
+
+ logger.logStr("New header target positions:")
+ logger.logIncomingHeader(incomingHeaderTarget)
+ logger.logMediaControls(mediaControlsTarget)
+ logger.logConversationsHeader(peopleHeaderTarget)
+ logger.logAlertingHeader(alertingHeaderTarget)
+ logger.logSilentHeader(gentleHeaderTarget)
+
+ // Add headers in reverse order to preserve indices
+ silentHeaderView?.let {
+ adjustHeaderVisibilityAndPosition(gentleHeaderTarget, it, currentGentleHeaderIdx)
+ }
+ alertingHeaderView?.let {
+ adjustHeaderVisibilityAndPosition(alertingHeaderTarget, it, currentAlertingHeaderIdx)
+ }
+ peopleHeaderView?.let {
+ adjustHeaderVisibilityAndPosition(peopleHeaderTarget, it, currentPeopleHeaderIdx)
+ }
+ incomingHeaderView?.let {
+ adjustHeaderVisibilityAndPosition(incomingHeaderTarget, it, currentIncomingHeaderIdx)
+ }
+ mediaControlsView?.let {
+ adjustViewPosition(mediaControlsTarget, it, currentMediaControlsIdx)
+ }
+
+ logger.logStr("Final order:")
+ logShadeContents()
+ logger.logStr("Section boundary update complete")
+
+ // Update headers to reflect state of section contents
+ silentHeaderView?.setAreThereDismissableGentleNotifs(
+ parent.hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
+ )
+ peopleHeaderView?.canSwipe = showHeaders && peopleHubVisible && !peopleNotifsPresent
+ if (peopleHeaderTarget != currentPeopleHeaderIdx) {
+ peopleHeaderView?.resetTranslation()
+ }
+ }
+
+ private fun adjustHeaderVisibilityAndPosition(
+ targetPosition: Int,
+ header: StackScrollerDecorView,
+ currentPosition: Int
+ ) {
+ adjustViewPosition(targetPosition, header, currentPosition)
+ if (targetPosition != -1 && currentPosition == -1) {
+ header.isContentVisible = true
+ }
+ }
+
+ private fun adjustViewPosition(
+ targetPosition: Int,
+ view: ExpandableView,
+ currentPosition: Int
+ ) {
+ if (targetPosition == -1) {
+ if (currentPosition != -1) {
+ parent.removeView(view)
+ }
+ } else {
+ if (currentPosition == -1) {
+ // If the header is animating away, it will still have a parent, so detach it first
+ // TODO: We should really cancel the active animations here. This will happen
+ // automatically when the view's intro animation starts, but it's a fragile link.
+ view.transientContainer?.removeTransientView(view)
+ view.transientContainer = null
+ parent.addView(view, targetPosition)
+ } else {
+ parent.changeViewPosition(view, targetPosition)
+ }
+ }
+ }
+
+ private sealed class SectionBounds {
+
+ data class Many(
+ val first: ActivatableNotificationView,
+ val last: ActivatableNotificationView
+ ) : SectionBounds()
+
+ data class One(val lone: ActivatableNotificationView) : SectionBounds()
+ object None : SectionBounds()
+
+ fun addNotif(notif: ActivatableNotificationView): SectionBounds = when (this) {
+ is None -> One(notif)
+ is One -> Many(lone, notif)
+ is Many -> copy(last = notif)
+ }
+
+ fun updateSection(section: NotificationSection): Boolean = when (this) {
+ is None -> section.setFirstAndLastVisibleChildren(null, null)
+ is One -> section.setFirstAndLastVisibleChildren(lone, lone)
+ is Many -> section.setFirstAndLastVisibleChildren(first, last)
+ }
+
+ private fun NotificationSection.setFirstAndLastVisibleChildren(
+ first: ActivatableNotificationView?,
+ last: ActivatableNotificationView?
+ ): Boolean {
+ val firstChanged = setFirstVisibleChild(first)
+ val lastChanged = setLastVisibleChild(last)
+ return firstChanged || lastChanged
+ }
+ }
+
+ /**
+ * Updates the boundaries (as tracked by their first and last views) of the priority sections.
+ *
+ * @return `true` If the last view in the top section changed (so we need to animate).
+ */
+ fun updateFirstAndLastViewsForAllSections(
+ sections: Array<NotificationSection>,
+ children: List<ActivatableNotificationView>
+ ): Boolean {
+ // Create mapping of bucket to section
+ val sectionBounds = children.asSequence()
+ // Group children by bucket
+ .groupingBy {
+ getBucket(it)
+ ?: throw IllegalArgumentException("Cannot find section bucket for view")
+ }
+ // Combine each bucket into a SectionBoundary
+ .foldToSparseArray(
+ SectionBounds.None,
+ size = sections.size,
+ operation = SectionBounds::addNotif
+ )
+ // Update each section with the associated boundary, tracking if there was a change
+ val changed = sections.fold(false) { changed, section ->
+ val bounds = sectionBounds[section.bucket] ?: SectionBounds.None
+ bounds.updateSection(section) || changed
+ }
+ if (DEBUG) {
+ logSections(sections)
+ }
+ return changed
+ }
+
+ private fun logSections(sections: Array<NotificationSection>) {
+ for (i in sections.indices) {
+ val s = sections[i]
+ val fs = when (val first = s.firstVisibleChild) {
+ null -> "(null)"
+ is ExpandableNotificationRow -> first.entry.key
+ else -> Integer.toHexString(System.identityHashCode(first))
+ }
+ val ls = when (val last = s.lastVisibleChild) {
+ null -> "(null)"
+ is ExpandableNotificationRow -> last.entry.key
+ else -> Integer.toHexString(System.identityHashCode(last))
+ }
+ Log.d(TAG, "updateSections: f=$fs s=$i")
+ Log.d(TAG, "updateSections: l=$ls s=$i")
+ }
+ }
+
+ private fun onGentleHeaderClick() {
+ val intent = Intent(Settings.ACTION_NOTIFICATION_SETTINGS)
+ activityStarter.startActivity(
+ intent,
+ true,
+ true,
+ Intent.FLAG_ACTIVITY_SINGLE_TOP)
+ }
+
+ private fun onClearGentleNotifsClick(v: View) {
+ onClearSilentNotifsClickListener?.onClick(v)
+ }
+
+ /** Listener for when the "clear all" button is clicked on the gentle notification header. */
+ fun setOnClearSilentNotifsClickListener(listener: View.OnClickListener) {
+ onClearSilentNotifsClickListener = listener
+ }
+
+ fun hidePeopleRow() {
+ peopleHubVisible = false
+ updateSectionBoundaries("PeopleHub dismissed")
+ }
+
+ fun setHeaderForegroundColor(@ColorInt color: Int) {
+ peopleHeaderView?.setTextColor(color)
+ silentHeaderView?.setForegroundColor(color)
+ alertingHeaderView?.setForegroundColor(color)
+ }
+
+ companion object {
+ private const val TAG = "NotifSectionsManager"
+ private const val DEBUG = false
+ private const val ENABLE_SNOOZED_CONVERSATION_HUB = false
+ }
+}
+
+/**
+ * For now, declare the available notification buckets (sections) here so that other
+ * presentation code can decide what to do based on an entry's buckets
+ */
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(
+ prefix = ["BUCKET_"],
+ value = [
+ BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
+ BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
+ ]
+)
+annotation class PriorityBucket
+
+const val BUCKET_UNKNOWN = 0
+const val BUCKET_MEDIA_CONTROLS = 1
+const val BUCKET_HEADS_UP = 2
+const val BUCKET_FOREGROUND_SERVICE = 3
+const val BUCKET_PEOPLE = 4
+const val BUCKET_ALERTING = 5
+const val BUCKET_SILENT = 6
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 7093dd8..3db4b6f 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
@@ -21,7 +21,7 @@
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
@@ -29,7 +29,6 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.app.TaskStackBuilder;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeAnimator;
@@ -51,9 +50,9 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -578,7 +577,7 @@
mSectionsManager = notificationSectionsManager;
mSectionsManager.initialize(this, LayoutInflater.from(context));
- mSectionsManager.setOnClearGentleNotifsClickListener(v -> {
+ mSectionsManager.setOnClearSilentNotifsClickListener(v -> {
// Leave the shade open if there will be other notifs left over to clear
final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY);
clearNotifications(ROWS_GENTLE, closeShade);
@@ -756,8 +755,8 @@
boolean showFooterView = (showDismissView || hasActiveNotifications())
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mRemoteInputManager.getController().isRemoteInputActive();
- boolean showHistory = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) == 1;
+ boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
updateFooterView(showFooterView, showDismissView, showHistory);
}
@@ -3073,6 +3072,9 @@
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean generateRemoveAnimation(ExpandableView child) {
+ if (!child.wantsAddAndRemoveAnimations()) {
+ return false;
+ }
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
mAddedHeadsUpChildren.remove(child);
return false;
@@ -3427,7 +3429,8 @@
@Override
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {
- if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress && !isFullyHidden()) {
+ if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress && !isFullyHidden()
+ && child.wantsAddAndRemoveAnimations()) {
// Generate Animations
mChildrenToAddAnimated.add(child);
if (fromMoreCard) {
@@ -5730,8 +5733,8 @@
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
view.setOnClickListener(v -> {
- final boolean showHistory = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) == 1;
+ final boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
Intent intent = showHistory ? new Intent(
Settings.ACTION_NOTIFICATION_HISTORY) : new Intent(
Settings.ACTION_NOTIFICATION_SETTINGS);
@@ -5840,7 +5843,7 @@
// Let's update the footer once the notifications have been updated (in the next frame)
post(() -> {
updateFooter();
- updateSectionBoundaries();
+ updateSectionBoundaries("dynamic privacy changed");
});
}
@@ -5921,8 +5924,8 @@
/** Updates the indices of the boundaries between sections. */
@ShadeViewRefactor(RefactorComponent.INPUT)
- public void updateSectionBoundaries() {
- mSectionsManager.updateSectionBoundaries();
+ public void updateSectionBoundaries(String reason) {
+ mSectionsManager.updateSectionBoundaries(reason);
}
private void updateContinuousBackgroundDrawing() {
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 6b0df95..3dcf7ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -439,7 +439,8 @@
// time out anyway
&& !entry.showingPulsing()) {
mEntriesToRemoveWhenReorderingAllowed.add(entry);
- mVisualStabilityManager.addReorderingAllowedCallback(HeadsUpManagerPhone.this);
+ mVisualStabilityManager.addReorderingAllowedCallback(HeadsUpManagerPhone.this,
+ false /* persistent */);
} else if (mTrackingHeadsUp) {
mEntriesToRemoveAfterExpand.add(entry);
} else if (mIsAutoHeadsUp && mStatusBarState == StatusBarState.KEYGUARD) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 84dd48b..80785db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import android.annotation.Nullable;
-import android.app.NotificationChannel;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
@@ -28,6 +27,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -42,6 +42,8 @@
import javax.inject.Inject;
import javax.inject.Singleton;
+import dagger.Lazy;
+
/**
* A class to handle notifications and their corresponding groups.
*/
@@ -51,6 +53,7 @@
private static final String TAG = "NotificationGroupManager";
private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
private final ArraySet<OnGroupChangeListener> mListeners = new ArraySet<>();
+ private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
private int mBarState = -1;
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
private HeadsUpManager mHeadsUpManager;
@@ -58,8 +61,11 @@
@Nullable private BubbleController mBubbleController = null;
@Inject
- public NotificationGroupManager(StatusBarStateController statusBarStateController) {
+ public NotificationGroupManager(
+ StatusBarStateController statusBarStateController,
+ Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier) {
statusBarStateController.addCallback(this);
+ mPeopleNotificationIdentifier = peopleNotificationIdentifier;
}
private BubbleController getBubbleController() {
@@ -536,8 +542,9 @@
if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
return false;
}
- NotificationChannel channel = entry.getChannel();
- if (channel != null && channel.isImportantConversation()) {
+ int peopleNotificationType = mPeopleNotificationIdentifier.get().getPeopleNotificationType(
+ entry.getSbn(), entry.getRanking());
+ if (peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON) {
return true;
}
if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) {
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 c9716d3..35c33ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -69,6 +69,7 @@
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -242,6 +243,7 @@
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final ConversationNotificationManager mConversationNotificationManager;
+ private final MediaHierarchyManager mMediaHierarchyManager;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -456,7 +458,8 @@
ConfigurationController configurationController,
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
- ConversationNotificationManager conversationNotificationManager) {
+ ConversationNotificationManager conversationNotificationManager,
+ MediaHierarchyManager mediaHierarchyManager) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -466,6 +469,7 @@
mZenModeController = zenModeController;
mConfigurationController = configurationController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
+ mMediaHierarchyManager = mediaHierarchyManager;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -1609,7 +1613,7 @@
if (mQs == null) return;
float qsExpansionFraction = getQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
- int heightDiff = mQs.getDesiredHeight() - mQs.getQsMinExpansionHeight();
+ mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
mNotificationStackScroller.setQsExpansionFraction(qsExpansionFraction);
}
@@ -2880,8 +2884,8 @@
return mNotificationStackScroller.createDelegate();
}
- public void updateNotificationViews() {
- mNotificationStackScroller.updateSectionBoundaries();
+ void updateNotificationViews(String reason) {
+ mNotificationStackScroller.updateSectionBoundaries(reason);
mNotificationStackScroller.updateSpeedBumpIndex();
mNotificationStackScroller.updateFooter();
updateShowEmptyShadeView();
@@ -3514,7 +3518,11 @@
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
if (mQs != null) {
+ float previousMin = mQsMinExpansionHeight;
mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
+ if (mQsExpansionHeight == previousMin) {
+ mQsExpansionHeight = mQsMinExpansionHeight;
+ }
mQsMaxExpansionHeight = mQs.getDesiredHeight();
mNotificationStackScroller.setMaxTopPadding(
mQsMaxExpansionHeight + mQsNotificationTopPadding);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index fc6a028..2e4a929d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -279,7 +279,7 @@
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
// Make sure to remove FLAG_ALT_FOCUSABLE_IM when keyguard needs input.
- if (state.mKeyguardNeedsInput) {
+ if (state.mKeyguardNeedsInput && state.isKeyguardShowingAndNotOccluded()) {
mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else {
mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -321,7 +321,8 @@
|| state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing
|| state.mHeadsUpShowing
|| state.mScrimsVisibility != ScrimController.TRANSPARENT)
- || state.mBackgroundBlurRadius > 0;
+ || state.mBackgroundBlurRadius > 0
+ || state.mLaunchingActivity;
}
private void applyFitsSystemWindows(State state) {
@@ -485,6 +486,11 @@
apply(mCurrentState);
}
+ void setLaunchingActivity(boolean launching) {
+ mCurrentState.mLaunchingActivity = launching;
+ apply(mCurrentState);
+ }
+
public void setScrimsVisibility(int scrimsVisibility) {
mCurrentState.mScrimsVisibility = scrimsVisibility;
apply(mCurrentState);
@@ -645,6 +651,7 @@
boolean mForceCollapsed;
boolean mForceDozeBrightness;
boolean mForceUserActivity;
+ boolean mLaunchingActivity;
boolean mBackdropShowing;
boolean mWallpaperSupportsAmbientMode;
boolean mNotTouchable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 596a607..42222d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -93,6 +93,7 @@
private PhoneStatusBarView mStatusBarView;
private PhoneStatusBarTransitions mBarTransitions;
private StatusBar mService;
+ private NotificationShadeWindowController mNotificationShadeWindowController;
private DragDownHelper mDragDownHelper;
private boolean mDoubleTapEnabled;
private boolean mSingleTapEnabled;
@@ -429,11 +430,19 @@
}
public void setExpandAnimationPending(boolean pending) {
- mExpandAnimationPending = pending;
+ if (mExpandAnimationPending != pending) {
+ mExpandAnimationPending = pending;
+ mNotificationShadeWindowController
+ .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
+ }
}
public void setExpandAnimationRunning(boolean running) {
- mExpandAnimationRunning = running;
+ if (mExpandAnimationRunning != running) {
+ mExpandAnimationRunning = running;
+ mNotificationShadeWindowController
+ .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
+ }
}
public void cancelExpandHelper() {
@@ -456,8 +465,9 @@
}
}
- public void setService(StatusBar statusBar) {
+ public void setService(StatusBar statusBar, NotificationShadeWindowController controller) {
mService = statusBar;
+ mNotificationShadeWindowController = controller;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d4f4d3b..a065b74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -663,6 +663,7 @@
if (DEBUG) Log.d(TAG, "screenrecord: countdown " + millisUntilFinished);
int countdown = (int) Math.floorDiv(millisUntilFinished + 500, 1000);
int resourceId = R.drawable.stat_sys_screen_record;
+ String description = Integer.toString(countdown);
switch (countdown) {
case 1:
resourceId = R.drawable.stat_sys_screen_record_1;
@@ -674,7 +675,7 @@
resourceId = R.drawable.stat_sys_screen_record_3;
break;
}
- mIconController.setIcon(mSlotScreenRecord, resourceId, null);
+ mIconController.setIcon(mSlotScreenRecord, resourceId, description);
mIconController.setIconVisibility(mSlotScreenRecord, true);
}
@@ -688,7 +689,8 @@
public void onRecordingStart() {
if (DEBUG) Log.d(TAG, "screenrecord: showing icon");
mIconController.setIcon(mSlotScreenRecord,
- R.drawable.stat_sys_screen_record, null);
+ R.drawable.stat_sys_screen_record,
+ mResources.getString(R.string.screenrecord_ongoing_screen_only));
mIconController.setIconVisibility(mSlotScreenRecord, true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
index 0147e7f..de9c745 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
@@ -29,6 +29,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.provider.Settings;
+import android.util.Log;
import android.view.IRotationWatcher.Stub;
import android.view.MotionEvent;
import android.view.Surface;
@@ -36,8 +37,9 @@
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -53,12 +55,13 @@
/** Contains logic that deals with showing a rotate suggestion button with animation. */
public class RotationButtonController {
+ private static final String TAG = "StatusBar/RotationButtonController";
private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
private static final int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
- private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
private final ViewRippler mViewRippler = new ViewRippler();
private @StyleRes int mStyleRes;
@@ -138,6 +141,9 @@
try {
WindowManagerGlobal.getWindowManagerService()
.watchRotation(mRotationWatcher, mContext.getDisplay().getDisplayId());
+ } catch (IllegalArgumentException e) {
+ mListenersRegistered = false;
+ Log.w(TAG, "RegisterListeners for the display failed");
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -318,7 +324,7 @@
}
private void onRotateSuggestionClick(View v) {
- mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
+ mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED);
incrementNumAcceptedRotationSuggestionsIfNeeded();
setRotationLockedAtAngle(mLastRotationSuggestion);
}
@@ -340,7 +346,7 @@
private void showAndLogRotationSuggestion() {
setRotateSuggestionButtonState(true /* visible */);
rescheduleRotationTimeout(false /* reasonHover */);
- mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
+ mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_SHOWN);
}
private boolean shouldOverrideUserLockPrefs(final int rotation) {
@@ -469,4 +475,19 @@
}
};
}
+
+ enum RotationButtonEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The rotation button was shown")
+ ROTATION_SUGGESTION_SHOWN(206),
+ @UiEvent(doc = "The rotation button was clicked")
+ ROTATION_SUGGESTION_ACCEPTED(207);
+
+ private final int mId;
+ RotationButtonEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c590139..33997b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -440,24 +440,7 @@
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
- applyExpansionToAlpha();
- if (mUpdatePending) {
- return;
- }
- setOrAdaptCurrentAnimation(mScrimBehind);
- setOrAdaptCurrentAnimation(mScrimInFront);
- setOrAdaptCurrentAnimation(mScrimForBubble);
- dispatchScrimState(mScrimBehind.getViewAlpha());
-
- // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
- // and docking.
- if (mWallpaperVisibilityTimedOut) {
- mWallpaperVisibilityTimedOut = false;
- DejankUtils.postAfterTraversal(() -> {
- mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
- AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
- });
- }
+ applyAndDispatchExpansion();
}
}
@@ -513,6 +496,27 @@
}
}
+ private void applyAndDispatchExpansion() {
+ applyExpansionToAlpha();
+ if (mUpdatePending) {
+ return;
+ }
+ setOrAdaptCurrentAnimation(mScrimBehind);
+ setOrAdaptCurrentAnimation(mScrimInFront);
+ setOrAdaptCurrentAnimation(mScrimForBubble);
+ dispatchScrimState(mScrimBehind.getViewAlpha());
+
+ // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
+ // and docking.
+ if (mWallpaperVisibilityTimedOut) {
+ mWallpaperVisibilityTimedOut = false;
+ DejankUtils.postAfterTraversal(() -> {
+ mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
+ AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ });
+ }
+ }
+
/**
* Sets the given drawable as the background of the scrim that shows up behind the
* notifications.
@@ -1006,6 +1010,9 @@
public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
mExpansionAffectsAlpha = expansionAffectsAlpha;
+ if (expansionAffectsAlpha) {
+ applyAndDispatchExpansion();
+ }
}
public void setKeyguardOccluded(boolean keyguardOccluded) {
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 bbf83bc..19de191 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1001,7 +1001,7 @@
updateTheme();
inflateStatusBarWindow();
- mNotificationShadeWindowViewController.setService(this);
+ mNotificationShadeWindowViewController.setService(this, mNotificationShadeWindowController);
mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener());
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
@@ -1488,7 +1488,7 @@
if (mDividerOptional.isPresent()) {
divider = mDividerOptional.get();
}
- if (divider == null || !divider.inSplitMode()) {
+ if (divider == null || !divider.isDividerVisible()) {
final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
if (navbarPos == NAV_BAR_POS_INVALID) {
return false;
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 d40b5f9..7924348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -285,18 +285,7 @@
mLogger.logHandleClickAfterKeyguardDismissed(sbn.getKey());
// TODO: Some of this code may be able to move to NotificationEntryManager.
- if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(sbn.getKey())) {
- // Release the HUN notification to the shade.
-
- if (mPresenter.isPresenterFullyCollapsed()) {
- HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
- }
- //
- // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
- // become canceled shortly by NoMan, but we can't assume that.
- mHeadsUpManager.removeNotification(sbn.getKey(),
- true /* releaseImmediately */);
- }
+ removeHUN(row);
NotificationEntry parentToCancel = null;
if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
NotificationEntry summarySbn = mGroupManager.getLogicalGroupSummary(sbn);
@@ -440,7 +429,9 @@
}
int launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
null, null, getActivityOptions(adapter));
- mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
+ mMainThreadHandler.post(() -> {
+ mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
+ });
} catch (RemoteException | PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -460,9 +451,14 @@
mActivityLaunchAnimator.getLaunchAnimation(
row, mStatusBar.isOccluded())),
new UserHandle(UserHandle.getUserId(appUid)));
- mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
+
+ // Putting it back on the main thread, since we're touching views
+ mMainThreadHandler.post(() -> {
+ mActivityLaunchAnimator.setLaunchResult(launchResult,
+ true /* isActivityIntent */);
+ removeHUN(row);
+ });
if (shouldCollapse()) {
- // Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
}
@@ -483,7 +479,7 @@
if (showHistory) {
tsb.addNextIntent(intent);
}
- tsb.startActivities();
+ tsb.startActivities(null, UserHandle.CURRENT);
if (shouldCollapse()) {
// Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
@@ -494,6 +490,20 @@
}, null, false /* afterKeyguardGone */);
}
+ private void removeHUN(ExpandableNotificationRow row) {
+ String key = row.getEntry().getSbn().getKey();
+ if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
+ // Release the HUN notification to the shade.
+ if (mPresenter.isPresenterFullyCollapsed()) {
+ HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
+ }
+
+ // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
+ // become canceled shortly by NoMan, but we can't assume that.
+ mHeadsUpManager.removeNotification(key, true /* releaseImmediately */);
+ }
+ }
+
private void handleFullScreenIntent(NotificationEntry entry) {
if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
if (shouldSuppressFullScreenIntent(entry)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index aecbb90..84da35b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -296,20 +296,20 @@
}
@Override
- public void updateNotificationViews() {
+ public void updateNotificationViews(final String reason) {
// The function updateRowStates depends on both of these being non-null, so check them here.
// We may be called before they are set from DeviceProvisionedController's callback.
if (mScrimController == null) return;
// Do not modify the notifications during collapse.
if (isCollapsing()) {
- mShadeController.addPostCollapseAction(this::updateNotificationViews);
+ mShadeController.addPostCollapseAction(() -> updateNotificationViews(reason));
return;
}
mViewHierarchyManager.updateNotificationViews();
- mNotificationPanel.updateNotificationViews();
+ mNotificationPanel.updateNotificationViews(reason);
}
public void onNotificationRemoved(String key, StatusBarNotification old) {
@@ -347,7 +347,7 @@
updateNotificationOnUiModeChanged();
mDispatchUiModeChangeOnUserSwitched = false;
}
- updateNotificationViews();
+ updateNotificationViews("user switched");
mMediaManager.clearCurrentMediaNotification();
mStatusBar.setLockscreenUser(newUserId);
updateMediaMetaData(true, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 428de9e..669e6a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -37,6 +37,7 @@
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -73,6 +74,7 @@
private View mPendingRemoteInputView;
private KeyguardManager mKeyguardManager;
private final CommandQueue mCommandQueue;
+ private final ActionClickLogger mActionClickLogger;
private int mDisabled2;
protected BroadcastReceiver mChallengeReceiver = new ChallengeReceiver();
private Handler mMainHandler = new Handler();
@@ -87,7 +89,8 @@
StatusBarStateController statusBarStateController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ActivityStarter activityStarter, ShadeController shadeController,
- CommandQueue commandQueue) {
+ CommandQueue commandQueue,
+ ActionClickLogger clickLogger) {
mContext = context;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mShadeController = shadeController;
@@ -101,6 +104,7 @@
mKeyguardManager = context.getSystemService(KeyguardManager.class);
mCommandQueue = commandQueue;
mCommandQueue.addCallback(this);
+ mActionClickLogger = clickLogger;
mActivityIntentHelper = new ActivityIntentHelper(mContext);
mGroupManager = groupManager;
// Listen to onKeyguardShowingChanged in case a managed profile needs to be unlocked
@@ -304,9 +308,12 @@
NotificationRemoteInputManager.ClickHandler defaultHandler) {
final boolean isActivity = pendingIntent.isActivity();
if (isActivity) {
+ mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent);
final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity(
pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
mActivityStarter.dismissKeyguardThenExecute(() -> {
+ mActionClickLogger.logKeyguardGone(pendingIntent);
+
try {
ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index a81189e..b9168e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -53,6 +53,11 @@
boolean isAodPowerSave();
/**
+ * Initializes the class.
+ */
+ default void init() { }
+
+ /**
* Returns {@code true} if reverse is supported.
*/
default boolean isReverseSupported() { return false; }
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 95b41a1..00419e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -80,7 +80,7 @@
@VisibleForTesting
@Inject
- protected BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+ public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
@Main Handler mainHandler, @Background Handler bgHandler) {
mContext = context;
@@ -89,10 +89,6 @@
mPowerManager = powerManager;
mEstimates = enhancedEstimates;
mBroadcastDispatcher = broadcastDispatcher;
-
- registerReceiver();
- updatePowerSave();
- updateEstimate();
}
private void registerReceiver() {
@@ -104,6 +100,13 @@
}
@Override
+ public void init() {
+ registerReceiver();
+ updatePowerSave();
+ updateEstimate();
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BatteryController state:");
pw.print(" mLevel="); pw.println(mLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index f8da03a..df3748a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -298,6 +298,7 @@
convertView.setAlpha(
item.isCurrent || item.isSwitchToEnabled ? USER_SWITCH_ENABLED_ALPHA
: USER_SWITCH_DISABLED_ALPHA);
+ convertView.setEnabled(item.isSwitchToEnabled);
return convertView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index a284335..f41a27c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -329,7 +329,8 @@
return mDataSaverController;
}
- private void registerListeners() {
+ @VisibleForTesting
+ void registerListeners() {
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.registerListener();
@@ -364,6 +365,18 @@
// Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast
// of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION
mReceiverHandler.post(mWifiSignalController::fetchInitialState);
+
+ // Initial setup of mLastServiceState. Only run if there is no service state yet.
+ // Each MobileSignalController will also get their corresponding
+ mReceiverHandler.post(() -> {
+ if (mLastServiceState == null) {
+ mLastServiceState = mPhone.getServiceState();
+ if (mMobileSignalControllers.size() == 0) {
+ recalculateEmergency();
+ }
+ }
+ });
+
updateMobileControllers();
// Initial setup of emergency information. Handled as if we had received a sticky broadcast
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 442c7ea..b6e72226 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -369,16 +369,24 @@
R.string.ext_media_new_notification_message, disk.getDescription());
final PendingIntent initIntent = buildInitPendingIntent(vol);
- return buildNotificationBuilder(vol, title, text)
- .addAction(new Action(R.drawable.ic_settings_24dp,
- mContext.getString(R.string.ext_media_init_action), initIntent))
- .addAction(new Action(R.drawable.ic_eject_24dp,
- mContext.getString(R.string.ext_media_unmount_action),
- buildUnmountPendingIntent(vol)))
- .setContentIntent(initIntent)
- .setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()))
- .build();
+ final PendingIntent unmountIntent = buildUnmountPendingIntent(vol);
+ if (isAutomotive()) {
+ return buildNotificationBuilder(vol, title, text)
+ .setContentIntent(unmountIntent)
+ .setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()))
+ .build();
+ } else {
+ return buildNotificationBuilder(vol, title, text)
+ .addAction(new Action(R.drawable.ic_settings_24dp,
+ mContext.getString(R.string.ext_media_init_action), initIntent))
+ .addAction(new Action(R.drawable.ic_eject_24dp,
+ mContext.getString(R.string.ext_media_unmount_action),
+ unmountIntent))
+ .setContentIntent(initIntent)
+ .setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()))
+ .build();
+ }
} else {
final CharSequence title = disk.getDescription();
final CharSequence text = mContext.getString(
@@ -427,9 +435,15 @@
R.string.ext_media_unmountable_notification_title, disk.getDescription());
final CharSequence text = mContext.getString(
R.string.ext_media_unmountable_notification_message, disk.getDescription());
+ PendingIntent action;
+ if (isAutomotive()) {
+ action = buildUnmountPendingIntent(vol);
+ } else {
+ action = buildInitPendingIntent(vol);
+ }
return buildNotificationBuilder(vol, title, text)
- .setContentIntent(buildInitPendingIntent(vol))
+ .setContentIntent(action)
.setCategory(Notification.CATEGORY_ERROR)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 367d4d2..2973e0a 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -23,15 +23,12 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
-import android.util.EventLog;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckBox;
-import android.widget.Toast;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
@@ -79,25 +76,6 @@
window.setCloseOnTouchOutside(false);
setupAlert();
-
- // adding touch listener on affirmative button - checks if window is obscured
- // if obscured, do not let user give permissions (could be tapjacking involved)
- final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
- // Filter obscured touches by consuming them.
- if (((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0)
- || ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0)) {
- if (event.getAction() == MotionEvent.ACTION_UP) {
- EventLog.writeEvent(0x534e4554, "62187985"); // safety net logging
- Toast.makeText(v.getContext(),
- R.string.touch_filtered_warning,
- Toast.LENGTH_SHORT).show();
- }
- return true;
- }
- return false;
- };
- mAlert.getButton(BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
-
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
similarity index 70%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
copy to packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
index d0f7607..c91033e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.UserIdInt
+package com.android.systemui.util
-data class BubbleXmlEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String
-)
+import android.view.ViewGroup
+
+/** [Sequence] that yields all of the direct children of this [ViewGroup] */
+val ViewGroup.children
+ get() = sequence {
+ for (i in 0 until childCount) yield(getChildAt(i))
+ }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt b/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
new file mode 100644
index 0000000..accb81e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.util
+
+import android.util.SparseArray
+
+/**
+ * Transforms an [Array] into a [SparseArray], by applying each element to [keySelector] in order to
+ * generate the index at which it will be placed. If two elements produce the same index, the latter
+ * replaces the former in the final result.
+ *
+ * See [Array.associateBy].
+ */
+inline fun <T> Array<T>.associateByToSparseArray(
+ crossinline keySelector: (T) -> Int
+): SparseArray<T> {
+ val sparseArray = SparseArray<T>(size)
+ for (value in this) {
+ sparseArray.put(keySelector(value), value)
+ }
+ return sparseArray
+}
+
+/**
+ * Folds a [Grouping] into a [SparseArray]. See [Grouping.fold].
+ */
+inline fun <T, R> Grouping<T, Int>.foldToSparseArray(
+ initial: R,
+ size: Int = -1,
+ crossinline operation: (R, T) -> R
+): SparseArray<R> {
+ val sparseArray = when {
+ size < 0 -> SparseArray<R>()
+ else -> SparseArray<R>(size)
+ }
+ sourceIterator().forEach { elem ->
+ val key = keyOf(elem)
+ val acc = sparseArray.get(key) ?: initial
+ sparseArray.put(key, operation(acc, elem))
+ }
+ return sparseArray
+}
+
+/**
+ * Wraps this [SparseArray] into an immutable [Map], the methods of which forward to this
+ * [SparseArray].
+ */
+fun <T> SparseArray<T>.asMap(): Map<Int, T> = SparseArrayMapWrapper(this)
+
+private class SparseArrayMapWrapper<T>(
+ private val sparseArray: SparseArray<T>
+) : Map<Int, T> {
+
+ private data class Entry<T>(override val key: Int, override val value: T) : Map.Entry<Int, T>
+
+ private val entrySequence = sequence {
+ val size = sparseArray.size()
+ for (i in 0 until size) {
+ val key = sparseArray.keyAt(i)
+ val value = sparseArray.get(key)
+ yield(Entry(key, value))
+ }
+ }
+
+ override val entries: Set<Map.Entry<Int, T>>
+ get() = object : Set<Map.Entry<Int, T>> {
+ override val size: Int
+ get() = this@SparseArrayMapWrapper.size
+
+ override fun contains(element: Map.Entry<Int, T>): Boolean =
+ sparseArray[element.key]?.let { it == element.value } == true
+
+ override fun containsAll(elements: Collection<Map.Entry<Int, T>>): Boolean =
+ elements.all { contains(it) }
+
+ override fun isEmpty(): Boolean = size == 0
+
+ override fun iterator(): Iterator<Map.Entry<Int, T>> = entrySequence.iterator()
+ }
+
+ override val keys: Set<Int> = object : Set<Int> {
+ private val keySequence = entrySequence.map { it.key }
+
+ override val size: Int
+ get() = this@SparseArrayMapWrapper.size
+
+ override fun contains(element: Int): Boolean = containsKey(element)
+
+ override fun containsAll(elements: Collection<Int>): Boolean =
+ elements.all { contains(it) }
+
+ override fun isEmpty(): Boolean = size == 0
+
+ override fun iterator(): Iterator<Int> = keySequence.iterator()
+ }
+ override val size: Int
+ get() = sparseArray.size()
+ override val values: Collection<T>
+ get() = object : Collection<T> {
+ private val valueSequence = entrySequence.map { it.value }
+
+ override val size: Int
+ get() = this@SparseArrayMapWrapper.size
+
+ override fun contains(element: T): Boolean = containsValue(element)
+
+ override fun containsAll(elements: Collection<T>): Boolean =
+ elements.all { contains(it) }
+
+ override fun isEmpty(): Boolean = this@SparseArrayMapWrapper.isEmpty()
+
+ override fun iterator(): Iterator<T> = valueSequence.iterator()
+ }
+
+ override fun containsKey(key: Int): Boolean = sparseArray.contains(key)
+
+ override fun containsValue(value: T): Boolean = sparseArray.indexOfValue(value) >= 0
+
+ override fun get(key: Int): T? = sparseArray.get(key)
+
+ override fun isEmpty(): Boolean = sparseArray.size() == 0
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 6a9d9b6..b1792d0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -130,7 +130,7 @@
*/
public static boolean useQsMediaPlayer(Context context) {
int flag = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0);
+ Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1);
return flag > 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/MeasurementCache.kt b/packages/SystemUI/src/com/android/systemui/util/animation/MeasurementCache.kt
new file mode 100644
index 0000000..2be698b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/MeasurementCache.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.util.animation
+
+/**
+ * A class responsible for caching view Measurements which guarantees that we always obtain a value
+ */
+class GuaranteedMeasurementCache constructor(
+ private val baseCache : MeasurementCache,
+ private val inputMapper: (MeasurementInput) -> MeasurementInput,
+ private val measurementProvider: (MeasurementInput) -> MeasurementOutput?
+) : MeasurementCache {
+
+ override fun obtainMeasurement(input: MeasurementInput) : MeasurementOutput {
+ val mappedInput = inputMapper.invoke(input)
+ if (!baseCache.contains(mappedInput)) {
+ var measurement = measurementProvider.invoke(mappedInput)
+ if (measurement != null) {
+ // Only cache measurings that actually have a size
+ baseCache.putMeasurement(mappedInput, measurement)
+ } else {
+ measurement = MeasurementOutput(0, 0)
+ }
+ return measurement
+ } else {
+ return baseCache.obtainMeasurement(mappedInput)
+ }
+ }
+
+ override fun contains(input: MeasurementInput): Boolean {
+ return baseCache.contains(inputMapper.invoke(input))
+ }
+
+ override fun putMeasurement(input: MeasurementInput, output: MeasurementOutput) {
+ if (output.measuredWidth == 0 || output.measuredHeight == 0) {
+ // Only cache measurings that actually have a size
+ return;
+ }
+ val remappedInput = inputMapper.invoke(input)
+ baseCache.putMeasurement(remappedInput, output)
+ }
+}
+
+/**
+ * A base implementation class responsible for caching view Measurements
+ */
+class BaseMeasurementCache : MeasurementCache {
+ private val dataCache: MutableMap<MeasurementInput, MeasurementOutput> = mutableMapOf()
+
+ override fun obtainMeasurement(input: MeasurementInput) : MeasurementOutput {
+ val measurementOutput = dataCache[input]
+ if (measurementOutput == null) {
+ return MeasurementOutput(0, 0)
+ } else {
+ return measurementOutput
+ }
+ }
+
+ override fun contains(input: MeasurementInput) : Boolean {
+ return dataCache[input] != null
+ }
+
+ override fun putMeasurement(input: MeasurementInput, output: MeasurementOutput) {
+ dataCache[input] = output
+ }
+}
+
+interface MeasurementCache {
+ fun obtainMeasurement(input: MeasurementInput) : MeasurementOutput
+ fun contains(input: MeasurementInput) : Boolean
+ fun putMeasurement(input: MeasurementInput, output: MeasurementOutput)
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index db08d64..5df5f40 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -311,10 +311,25 @@
val springConfigCopy = springConfig.copy()
val toAtLeast = if (startVelocity < 0) flingConfig.min else flingConfig.max
- // If the fling needs to reach min/max, calculate the velocity required to do so and use
- // that if the provided start velocity is not sufficient.
- if (flingMustReachMinOrMax &&
- toAtLeast != -Float.MAX_VALUE && toAtLeast != Float.MAX_VALUE) {
+ if (flingMustReachMinOrMax && isValidValue(toAtLeast)) {
+ val currentValue = property.getValue(target)
+ val flingTravelDistance =
+ startVelocity / (flingConfig.friction * FLING_FRICTION_SCALAR_MULTIPLIER)
+ val projectedFlingEndValue = currentValue + flingTravelDistance
+ val midpoint = (flingConfig.min + flingConfig.max) / 2
+
+ // If fling velocity is too low to push the target past the midpoint between min and
+ // max, then spring back towards the nearest edge, starting with the current velocity.
+ if ((startVelocity < 0 && projectedFlingEndValue > midpoint) ||
+ (startVelocity > 0 && projectedFlingEndValue < midpoint)) {
+ val toPosition =
+ if (projectedFlingEndValue < midpoint) flingConfig.min else flingConfig.max
+ if (isValidValue(toPosition)) {
+ return spring(property, toPosition, startVelocity, springConfig)
+ }
+ }
+
+ // Projected fling end value is past the midpoint, so fling forward.
val distanceToDestination = toAtLeast - property.getValue(target)
// The minimum velocity required for the fling to end up at the given destination,
@@ -345,6 +360,8 @@
return this
}
+ private fun isValidValue(value: Float) = value < Float.MAX_VALUE && value > -Float.MAX_VALUE
+
/**
* Adds a listener that will be called whenever any property on the animated object is updated.
* This will be called on every animation frame, with the current value of the animated object
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt b/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
new file mode 100644
index 0000000..bf94c5d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
@@ -0,0 +1,108 @@
+/*
+ * 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.util.animation
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.View
+import android.widget.FrameLayout
+
+/**
+ * A special view that is designed to host a single "unique object". The unique object is
+ * dynamically added and removed from this view and may transition to other UniqueObjectHostViews
+ * available in the system.
+ * This is useful to share a singular instance of a view that can transition between completely
+ * independent parts of the view hierarchy.
+ * If the view currently hosts the unique object, it's measuring it normally,
+ * but if it's not attached, it will obtain the size by requesting a measure, as if it were
+ * always attached.
+ */
+class UniqueObjectHostView(
+ context: Context
+) : FrameLayout(context) {
+ lateinit var measurementCache : GuaranteedMeasurementCache
+ var onMeasureListener: ((MeasurementInput) -> Unit)? = null
+
+ @SuppressLint("DrawAllocation")
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val paddingHorizontal = paddingStart + paddingEnd
+ val paddingVertical = paddingTop + paddingBottom
+ val width = MeasureSpec.getSize(widthMeasureSpec) - paddingHorizontal
+ val widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.getMode(widthMeasureSpec))
+ val height = MeasureSpec.getSize(heightMeasureSpec) - paddingVertical
+ val heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.getMode(heightMeasureSpec))
+ val measurementInput = MeasurementInputData(widthSpec, heightSpec)
+ onMeasureListener?.apply {
+ invoke(measurementInput)
+ }
+ if (!isCurrentHost()) {
+ // We're not currently the host, let's get the dimension from our cache (this might
+ // perform a measuring if the cache doesn't have it yet)
+ // The goal here is that the view will always have a consistent measuring, regardless
+ // if it's attached or not.
+ // The behavior is therefore very similar to the view being persistently attached to
+ // this host, which can prevent flickers. It also makes sure that we always know
+ // the size of the view during transitions even if it has never been attached here
+ // before.
+ val (cachedWidth, cachedHeight) = measurementCache.obtainMeasurement(measurementInput)
+ setMeasuredDimension(cachedWidth + paddingHorizontal, cachedHeight + paddingVertical)
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ // Let's update our cache
+ val child = getChildAt(0)!!
+ val output = MeasurementOutput(child.measuredWidth, child.measuredHeight)
+ measurementCache.putMeasurement(measurementInput, output)
+ }
+ }
+
+ private fun isCurrentHost() = childCount != 0
+}
+
+/**
+ * A basic view measurement input
+ */
+interface MeasurementInput {
+ fun sameAs(input: MeasurementInput?): Boolean {
+ return equals(input)
+ }
+ val width : Int
+ get() {
+ return View.MeasureSpec.getSize(widthMeasureSpec)
+ }
+ val height : Int
+ get() {
+ return View.MeasureSpec.getSize(heightMeasureSpec)
+ }
+ var widthMeasureSpec: Int
+ var heightMeasureSpec: Int
+}
+
+/**
+ * The output of a view measurement
+ */
+data class MeasurementOutput(
+ val measuredWidth: Int,
+ val measuredHeight: Int
+)
+
+/**
+ * The data object holding a basic view measurement input
+ */
+data class MeasurementInputData(
+ override var widthMeasureSpec: Int,
+ override var heightMeasureSpec: Int
+) : MeasurementInput
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
index 8acfbf2..7729965 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -23,6 +23,7 @@
import android.os.Process;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -50,6 +51,17 @@
return thread.getLooper();
}
+ /** Long running tasks Looper */
+ @Provides
+ @Singleton
+ @LongRunning
+ public static Looper provideLongRunningLooper() {
+ HandlerThread thread = new HandlerThread("SysUiLng",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ return thread.getLooper();
+ }
+
/** Main Looper */
@Provides
@Main
@@ -89,6 +101,16 @@
}
/**
+ * Provide a Long running Executor by default.
+ */
+ @Provides
+ @Singleton
+ @LongRunning
+ public static Executor provideLongRunningExecutor(@LongRunning Looper looper) {
+ return new ExecutorImpl(looper);
+ }
+
+ /**
* Provide a Background-Thread Executor.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 64cac84..21f67ae 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -125,7 +125,7 @@
*/
public void removeView(View view) {
SurfaceControlViewHost root = mViewRoots.remove(view);
- root.die();
+ root.release();
}
/**
@@ -189,8 +189,8 @@
public SurfaceControl getViewSurface(View rootView) {
for (int i = 0; i < mPerDisplay.size(); ++i) {
for (int iWm = 0; iWm < mPerDisplay.valueAt(i).mWwms.size(); ++iWm) {
- SurfaceControl out =
- mPerDisplay.valueAt(i).mWwms.get(iWm).getSurfaceControlForWindow(rootView);
+ SurfaceControl out = mPerDisplay.valueAt(i).mWwms.valueAt(iWm)
+ .getSurfaceControlForWindow(rootView);
if (out != null) {
return out;
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 12c7048..9c94b86 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -69,6 +69,11 @@
android:exported="false"
android:resizeableActivity="true" />
+ <activity
+ android:name="com.android.systemui.globalactions.GlobalActionsImeTest$TestActivity"
+ android:excludeFromRecents="true"
+ android:exported="false" />
+
<provider
android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
tools:replace="android:authorities"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 870010a..aa4122f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -134,6 +134,7 @@
mDependency.injectMockDependency(WakefulnessLifecycle.class);
mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
new Handler(mTestableLooper.getLooper()));
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor)
@@ -150,6 +151,7 @@
// This should not start listening on any of the real dependencies but will test that
// callbacks in mKeyguardUpdateMonitor are done in the mTestableLooper thread
mCarrierTextController.setListening(mCarrierTextCallback);
+ mTestableLooper.processAllMessages();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
deleted file mode 100644
index 4bcf917..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
+++ /dev/null
@@ -1,176 +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.keyguard
-
-import android.app.Notification
-import android.graphics.drawable.Icon
-import android.media.MediaMetadata
-import android.media.session.MediaController
-import android.media.session.MediaSession
-import android.media.session.PlaybackState
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.View
-import android.widget.TextView
-import androidx.arch.core.executor.ArchTaskExecutor
-import androidx.arch.core.executor.TaskExecutor
-import androidx.test.filters.SmallTest
-
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
-import com.android.systemui.media.MediaControllerFactory
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.any
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-public class KeyguardMediaPlayerTest : SysuiTestCase() {
-
- private lateinit var keyguardMediaPlayer: KeyguardMediaPlayer
- @Mock private lateinit var mockMediaFactory: MediaControllerFactory
- @Mock private lateinit var mockMediaController: MediaController
- private lateinit var playbackState: PlaybackState
- private lateinit var fakeExecutor: FakeExecutor
- private lateinit var mediaMetadata: MediaMetadata.Builder
- private lateinit var entry: NotificationEntry
- @Mock private lateinit var mockView: View
- private lateinit var songView: TextView
- private lateinit var artistView: TextView
- @Mock private lateinit var mockIcon: Icon
-
- private val taskExecutor: TaskExecutor = object : TaskExecutor() {
- public override fun executeOnDiskIO(runnable: Runnable) {
- runnable.run()
- }
- public override fun postToMainThread(runnable: Runnable) {
- runnable.run()
- }
- public override fun isMainThread(): Boolean {
- return true
- }
- }
-
- @Before
- public fun setup() {
- playbackState = PlaybackState.Builder().run {
- build()
- }
- mockMediaController = mock(MediaController::class.java)
- whenever(mockMediaController.getPlaybackState()).thenReturn(playbackState)
- mockMediaFactory = mock(MediaControllerFactory::class.java)
- whenever(mockMediaFactory.create(any())).thenReturn(mockMediaController)
-
- fakeExecutor = FakeExecutor(FakeSystemClock())
- keyguardMediaPlayer = KeyguardMediaPlayer(context, mockMediaFactory, fakeExecutor)
- mockIcon = mock(Icon::class.java)
-
- mockView = mock(View::class.java)
- songView = TextView(context)
- artistView = TextView(context)
- whenever<TextView>(mockView.findViewById(R.id.header_title)).thenReturn(songView)
- whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(artistView)
-
- mediaMetadata = MediaMetadata.Builder()
- entry = NotificationEntryBuilder().build()
- entry.getSbn().getNotification().extras.putParcelable(Notification.EXTRA_MEDIA_SESSION,
- MediaSession.Token(1, null))
-
- ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
-
- keyguardMediaPlayer.bindView(mockView)
- }
-
- @After
- public fun tearDown() {
- keyguardMediaPlayer.unbindView()
- ArchTaskExecutor.getInstance().setDelegate(null)
- }
-
- @Test
- public fun testBind() {
- keyguardMediaPlayer.unbindView()
- keyguardMediaPlayer.bindView(mockView)
- }
-
- @Test
- public fun testUnboundClearControls() {
- keyguardMediaPlayer.unbindView()
- keyguardMediaPlayer.clearControls()
- keyguardMediaPlayer.bindView(mockView)
- }
-
- @Test
- public fun testUpdateControls() {
- keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())
- FakeExecutor.exhaustExecutors(fakeExecutor)
- verify(mockView).setVisibility(View.VISIBLE)
- }
-
- @Test
- public fun testClearControls() {
- keyguardMediaPlayer.clearControls()
- FakeExecutor.exhaustExecutors(fakeExecutor)
- verify(mockView).setVisibility(View.GONE)
- }
-
- @Test
- public fun testUpdateControlsNullPlaybackState() {
- // GIVEN that the playback state is null (ie. the media session was destroyed)
- whenever(mockMediaController.getPlaybackState()).thenReturn(null)
- // WHEN updated
- keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())
- FakeExecutor.exhaustExecutors(fakeExecutor)
- // THEN the controls are cleared (ie. visibility is set to GONE)
- verify(mockView).setVisibility(View.GONE)
- }
-
- @Test
- public fun testSongName() {
- val song: String = "Song"
- mediaMetadata.putText(MediaMetadata.METADATA_KEY_TITLE, song)
-
- keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())
-
- assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
- assertThat(songView.getText()).isEqualTo(song)
- }
-
- @Test
- public fun testArtistName() {
- val artist: String = "Artist"
- mediaMetadata.putText(MediaMetadata.METADATA_KEY_ARTIST, artist)
-
- keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())
-
- assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
- assertThat(artistView.getText()).isEqualTo(artist)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 64590fd..e324d84 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -16,31 +16,75 @@
package com.android.keyguard;
+import static android.view.WindowInsets.Type.ime;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
-import android.test.UiThreadTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.LayoutInflater;
+import android.view.WindowInsetsController;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper()
public class KeyguardSecurityContainerTest extends SysuiTestCase {
- @UiThreadTest
+ @Mock
+ private KeyguardSecurityModel mKeyguardSecurityModel;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
+ @Mock
+ private KeyguardSecurityView mSecurityView;
+ @Mock
+ private WindowInsetsController mWindowInsetsController;
+ @Mock
+ private KeyguardSecurityViewFlipper mSecurityViewFlipper;
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+ private KeyguardSecurityContainer mKeyguardSecurityContainer;
+
+ @Before
+ public void setup() {
+ mDependency.injectTestDependency(KeyguardStateController.class, mKeyguardStateController);
+ mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel);
+ mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
+ mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()) {
+ @Override
+ protected KeyguardSecurityView getSecurityView(
+ KeyguardSecurityModel.SecurityMode securityMode) {
+ return mSecurityView;
+ }
+ };
+ mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+ when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+ mKeyguardSecurityContainer.setSecurityCallback(mSecurityCallback);
+ }
+
@Test
public void showSecurityScreen_canInflateAllModes() {
- mDependency.injectMockDependency(KeyguardStateController.class);
- KeyguardSecurityContainer keyguardSecurityContainer =
- new KeyguardSecurityContainer(getContext());
-
Context context = getContext();
for (int theme : new int[] {R.style.Theme_SystemUI, R.style.Theme_SystemUI_Light}) {
@@ -49,7 +93,7 @@
KeyguardSecurityModel.SecurityMode[] modes =
KeyguardSecurityModel.SecurityMode.values();
for (KeyguardSecurityModel.SecurityMode mode : modes) {
- final int resId = keyguardSecurityContainer.getLayoutIdFor(mode);
+ final int resId = mKeyguardSecurityContainer.getLayoutIdFor(mode);
if (resId == 0) {
continue;
}
@@ -57,4 +101,15 @@
}
}
}
+
+ @Test
+ public void startDisappearAnimation_animatesKeyboard() {
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
+ KeyguardSecurityModel.SecurityMode.Password);
+ mKeyguardSecurityContainer.showPrimarySecurityScreen(false /* turningOff */);
+
+ mKeyguardSecurityContainer.startDisappearAnimation(null);
+ verify(mSecurityView).startDisappearAnimation(eq(null));
+ verify(mWindowInsetsController).hide(eq(ime()));
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 6c00eca..7bc453a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -38,6 +38,7 @@
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
+import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -70,11 +71,16 @@
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.widget.ILockSettings;
+import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.RingerModeTracker;
@@ -87,6 +93,7 @@
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import java.util.ArrayList;
import java.util.List;
@@ -116,6 +123,10 @@
@Mock
private TrustManager mTrustManager;
@Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private ILockSettings mLockSettings;
+ @Mock
private FingerprintManager mFingerprintManager;
@Mock
private FaceManager mFaceManager;
@@ -134,16 +145,19 @@
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
private RingerModeTracker mRingerModeTracker;
@Mock
private LiveData<Integer> mRingerModeLiveData;
@Mock
- private TelephonyManager mTelephonyManager;
+ private StatusBarStateController mStatusBarStateController;
// Direct executor
private Executor mBackgroundExecutor = Runnable::run;
private TestableLooper mTestableLooper;
private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
private TestableContext mSpiedContext;
+ private MockitoSession mMockitoSession;
@Before
public void setup() {
@@ -162,9 +176,13 @@
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
when(mUserManager.isPrimaryUser()).thenReturn(true);
+ when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class));
when(mStrongAuthTracker
.isUnlockingWithBiometricAllowed(anyBoolean() /* isStrongBiometric */))
.thenReturn(true);
+ when(mTelephonyManager.getServiceStateForSubscriber(anyInt()))
+ .thenReturn(new ServiceState());
+ when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings);
mSpiedContext.addMockSystemService(TrustManager.class, mTrustManager);
mSpiedContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
mSpiedContext.addMockSystemService(BiometricManager.class, mBiometricManager);
@@ -176,6 +194,11 @@
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
+ mMockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(SubscriptionManager.class).startMocking();
+ ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .when(SubscriptionManager::getDefaultSubscriptionId);
+
mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread();
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
@@ -183,6 +206,7 @@
@After
public void tearDown() {
+ mMockitoSession.finishMocking();
mKeyguardUpdateMonitor.destroy();
}
@@ -406,6 +430,16 @@
}
@Test
+ public void skipsAuthentication_whenStatusBarShadeLocked() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+ mTestableLooper.processAllMessages();
+ mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+ verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+ }
+
+ @Test
public void skipsAuthentication_whenEncryptedKeyguard() {
when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
@@ -703,8 +737,9 @@
super(context,
TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
mBroadcastDispatcher, mDumpManager,
- mRingerModeTracker, mBackgroundExecutor);
- mStrongAuthTracker = KeyguardUpdateMonitorTest.this.mStrongAuthTracker;
+ mRingerModeTracker, mBackgroundExecutor,
+ mStatusBarStateController, mLockPatternUtils);
+ setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
public boolean hasSimStateJustChanged() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index fc1ddf7..821b850 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -470,7 +470,8 @@
true /* requireConfirmation */,
0 /* userId */,
"testPackage",
- 0 /* operationId */);
+ 0 /* operationId */,
+ 0 /* sysUiSessionId */);
}
private Bundle createTestDialogBundle(int authenticators) {
@@ -508,7 +509,7 @@
@Override
protected AuthDialog buildDialog(Bundle biometricPromptBundle,
boolean requireConfirmation, int userId, int type, String opPackageName,
- boolean skipIntro, long operationId) {
+ boolean skipIntro, long operationId, int sysUiSessionId) {
mLastBiometricPromptBundle = biometricPromptBundle;
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 e2f303e..96e868d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -279,7 +279,8 @@
mFloatingContentCoordinator,
mDataRepository,
mSysUiState,
- mock(INotificationManager.class));
+ mock(INotificationManager.class),
+ mWindowManager);
mBubbleController.setExpandListener(mBubbleExpandListener);
// Get a reference to the BubbleController's entry listener
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 8a83b84..73b8760 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -254,7 +254,8 @@
mFloatingContentCoordinator,
mDataRepository,
mSysUiState,
- mock(INotificationManager.class));
+ mock(INotificationManager.class),
+ mWindowManager);
mBubbleController.addNotifCallback(mNotifCallback);
mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index 1542b86..bdb7944 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -18,6 +18,7 @@
import android.app.INotificationManager;
import android.content.Context;
+import android.view.WindowManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -57,13 +58,15 @@
FloatingContentCoordinator floatingContentCoordinator,
BubbleDataRepository dataRepository,
SysUiState sysUiState,
- INotificationManager notificationManager) {
+ INotificationManager notificationManager,
+ WindowManager windowManager) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
zenModeController, lockscreenUserManager, groupManager, entryManager,
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
- dataRepository, sysUiState, notificationManager);
+ dataRepository, sysUiState, notificationManager,
+ windowManager);
setInflateSynchronously(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
new file mode 100644
index 0000000..d49d021
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles.storage
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BubblePersistentRepositoryTest : SysuiTestCase() {
+
+ private val bubbles = listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1"),
+ BubbleEntity(10, "com.example.chat", "alice and bob"),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2")
+ )
+ private lateinit var repository: BubblePersistentRepository
+
+ @Before
+ fun setup() {
+ repository = BubblePersistentRepository(mContext)
+ }
+
+ @Test
+ fun testReadWriteOperation() {
+ repository.persistsToDisk(bubbles)
+ assertEquals(bubbles, repository.readFromDisk())
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
new file mode 100644
index 0000000..7acc937
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles.storage
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BubbleVolatileRepositoryTest : SysuiTestCase() {
+
+ private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1")
+ private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob")
+ private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2")
+ private val bubbles = listOf(bubble1, bubble2, bubble3)
+
+ private lateinit var repository: BubbleVolatileRepository
+
+ @Before
+ fun setup() {
+ repository = BubbleVolatileRepository()
+ }
+
+ @Test
+ fun testAddAndRemoveBubbles() {
+ repository.addBubbles(bubbles)
+ assertEquals(bubbles, repository.bubbles)
+ repository.addBubbles(listOf(bubble1))
+ assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles)
+ repository.removeBubbles(listOf(bubble3))
+ assertEquals(listOf(bubble2, bubble1), repository.bubbles)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
new file mode 100644
index 0000000..ef4580c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles.storage
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BubbleXmlHelperTest : SysuiTestCase() {
+
+ private val bubbles = listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1"),
+ BubbleEntity(10, "com.example.chat", "alice and bob"),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2")
+ )
+
+ @Test
+ fun testWriteXml() {
+ val expectedEntries = """
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" />
+ """.trimIndent()
+ ByteArrayOutputStream().use {
+ writeXml(it, bubbles)
+ val actual = it.toString()
+ assertTrue("cannot find expected entry in \n$actual",
+ actual.contains(expectedEntries))
+ }
+ }
+
+ @Test
+ fun testReadXml() {
+ val src = """
+ <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+ <bs>
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" />
+ </bs>
+ """.trimIndent()
+ val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
+ assertEquals("failed parsing bubbles from xml\n$src", bubbles, actual)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 9b40c5e..128a7e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -177,4 +177,31 @@
inOrder.verify(mockSL).setListening(true)
inOrder.verify(mockSL).reload()
}
-}
\ No newline at end of file
+
+ @Test
+ fun testChangeUserResetsExistingCallbackServices() {
+ val list = listOf(serviceInfo)
+ controller.addCallback(mockCallback)
+
+ @Suppress("unchecked_cast")
+ val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
+ ArgumentCaptor.forClass(List::class.java)
+ as ArgumentCaptor<List<ControlsServiceInfo>>
+ executor.runAllReady()
+ reset(mockCallback)
+
+ serviceListingCallbackCaptor.value.onServicesReloaded(list)
+
+ executor.runAllReady()
+ verify(mockCallback).onServicesUpdated(capture(captor))
+ assertEquals(1, captor.value.size)
+
+ reset(mockCallback)
+ controller.changeUser(UserHandle.of(otherUser))
+ executor.runAllReady()
+ assertEquals(otherUser, controller.currentUserId)
+
+ verify(mockCallback).onServicesUpdated(capture(captor))
+ assertEquals(0, captor.value.size)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index 64acdcc..4a85980 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -53,6 +53,7 @@
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.controls.ui.ControlsUiController;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.statusbar.BlurUtils;
@@ -107,6 +108,7 @@
@Mock private UiEventLogger mUiEventLogger;
@Mock private RingerModeTracker mRingerModeTracker;
@Mock private RingerModeLiveData mRingerModeLiveData;
+ @Mock private SysUiState mSysUiState;
@Mock private Handler mHandler;
private TestableLooper mTestableLooper;
@@ -150,19 +152,27 @@
mControlsController,
mUiEventLogger,
mRingerModeTracker,
+ mSysUiState,
mHandler
);
mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
}
@Test
- public void testShouldLogVisibility() {
+ public void testShouldLogShow() {
mGlobalActionsDialog.onShow(null);
mTestableLooper.processAllMessages();
verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN);
}
@Test
+ public void testShouldLogDismiss() {
+ mGlobalActionsDialog.onDismiss(mGlobalActionsDialog.mDialog);
+ mTestableLooper.processAllMessages();
+ verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_CLOSE);
+ }
+
+ @Test
public void testShouldLogBugreportPress() throws InterruptedException {
GlobalActionsDialog.BugReportAction bugReportAction =
mGlobalActionsDialog.makeBugReportActionForTesting();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
new file mode 100644
index 0000000..eb43b81
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.globalactions;
+
+import static android.view.WindowInsets.Type.ime;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.BooleanSupplier;
+
+@LargeTest
+public class GlobalActionsImeTest extends SysuiTestCase {
+
+ @Rule
+ public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(
+ TestActivity.class, false, false);
+
+ /**
+ * This test verifies that GlobalActions, which is frequently used to capture bugreports,
+ * doesn't interfere with the IME, i.e. soft-keyboard state.
+ */
+ @Test
+ public void testGlobalActions_doesntStealImeControl() {
+ final TestActivity activity = mActivityTestRule.launchActivity(null);
+
+ activity.waitFor(() -> activity.mHasFocus && activity.mControlsIme && activity.mImeVisible);
+
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ "input keyevent --longpress POWER"
+ );
+
+ activity.waitFor(() -> !activity.mHasFocus);
+ // Give the dialog time to animate in, and steal IME focus. Unfortunately, there's currently
+ // no better way to wait for this.
+ SystemClock.sleep(TimeUnit.SECONDS.toMillis(2));
+
+ runAssertionOnMainThread(() -> {
+ assertTrue("IME should remain visible behind GlobalActions, but didn't",
+ activity.mControlsIme);
+ assertTrue("App behind GlobalActions should remain in control of IME, but didn't",
+ activity.mImeVisible);
+ });
+ }
+
+ /** Like Instrumentation.runOnMainThread(), but forwards AssertionErrors to the caller. */
+ private static void runAssertionOnMainThread(Runnable r) {
+ AssertionError[] t = new AssertionError[1];
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ try {
+ r.run();
+ } catch (AssertionError e) {
+ t[0] = e;
+ // Ignore assertion - throwing it here would crash the main thread.
+ }
+ });
+ if (t[0] != null) {
+ throw t[0];
+ }
+ }
+
+ public static class TestActivity extends Activity implements
+ WindowInsetsController.OnControllableInsetsChangedListener,
+ View.OnApplyWindowInsetsListener {
+
+ private EditText mContent;
+ boolean mHasFocus;
+ boolean mControlsIme;
+ boolean mImeVisible;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mContent = new EditText(this);
+ mContent.setCursorVisible(false); // Otherwise, main thread doesn't go idle.
+ setContentView(mContent);
+ mContent.requestFocus();
+
+ getWindow().getDecorView().setOnApplyWindowInsetsListener(this);
+ WindowInsetsController wic = mContent.getWindowInsetsController();
+ wic.addOnControllableInsetsChangedListener(this);
+ wic.show(ime());
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ synchronized (this) {
+ mHasFocus = hasFocus;
+ notifyAll();
+ }
+ }
+
+ @Override
+ public void onControllableInsetsChanged(@NonNull WindowInsetsController controller,
+ int typeMask) {
+ synchronized (this) {
+ mControlsIme = (typeMask & ime()) != 0;
+ notifyAll();
+ }
+ }
+
+ void waitFor(BooleanSupplier condition) {
+ synchronized (this) {
+ while (!condition.getAsBoolean()) {
+ try {
+ wait(TimeUnit.SECONDS.toMillis(5));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ mImeVisible = insets.isVisible(ime());
+ return v.onApplyWindowInsets(insets);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 92c1d76..f70fb4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -131,7 +131,7 @@
MediaMetadata metadata = mock(MediaMetadata.class);
when(metadata.getText(any())).thenReturn("metadata");
mProvider.onDozingChanged(true);
- mProvider.onMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING);
+ mProvider.onPrimaryMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING);
mProvider.onBindSlice(mProvider.getUri());
verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE));
verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_ARTIST));
@@ -144,7 +144,7 @@
when(metadata.getText(any())).thenReturn("metadata");
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
- mProvider.onMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING);
+ mProvider.onPrimaryMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING);
mProvider.onBindSlice(mProvider.getUri());
verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE));
verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_ARTIST));
@@ -210,7 +210,8 @@
mProvider.onStateChanged(StatusBarState.KEYGUARD);
mProvider.onDozingChanged(true);
reset(mContentResolver);
- mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING);
+ mProvider.onPrimaryMetadataOrStateChanged(mock(MediaMetadata.class),
+ PlaybackState.STATE_PLAYING);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
// Hides after waking up
@@ -222,7 +223,8 @@
@Test
public void onDozingChanged_updatesSliceIfMedia() {
mProvider.onStateChanged(StatusBarState.KEYGUARD);
- mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING);
+ mProvider.onPrimaryMetadataOrStateChanged(mock(MediaMetadata.class),
+ PlaybackState.STATE_PLAYING);
reset(mContentResolver);
// Show media when dozing
mProvider.onDozingChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/PlayerViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/PlayerViewHolderTest.kt
new file mode 100644
index 0000000..7678525
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/PlayerViewHolderTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.media
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.FrameLayout
+
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for PlayerViewHolder.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class PlayerViewHolderTest : SysuiTestCase() {
+
+ private lateinit var inflater: LayoutInflater
+ private lateinit var parent: ViewGroup
+
+ @Before
+ fun setUp() {
+ inflater = LayoutInflater.from(context)
+ parent = FrameLayout(context)
+ }
+
+ @Test
+ fun create() {
+ val holder = PlayerViewHolder.create(inflater, parent)
+ assertThat(holder.player).isNotNull()
+ }
+
+ @Test
+ fun backgroundIsIlluminationDrawable() {
+ val holder = PlayerViewHolder.create(inflater, parent)
+ assertThat(holder.background.background as IlluminationDrawable).isNotNull()
+ }
+}
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 d407b8a..58ee79e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -16,19 +16,15 @@
package com.android.systemui.media
-import android.graphics.Color
-import android.content.res.ColorStateList
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.widget.SeekBar
import android.widget.TextView
import androidx.test.filters.SmallTest
-
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
-
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,7 +61,7 @@
fun seekBarGone() {
// WHEN seek bar is disabled
val isEnabled = false
- val data = SeekBarViewModel.Progress(isEnabled, false, null, null, null)
+ val data = SeekBarViewModel.Progress(isEnabled, false, null, null)
observer.onChanged(data)
// THEN seek bar shows just a line with no text
assertThat(seekBarView.isEnabled()).isFalse()
@@ -78,7 +74,7 @@
fun seekBarVisible() {
// WHEN seek bar is enabled
val isEnabled = true
- val data = SeekBarViewModel.Progress(isEnabled, true, 3000, 12000, -1)
+ val data = SeekBarViewModel.Progress(isEnabled, true, 3000, 12000)
observer.onChanged(data)
// THEN seek bar is visible
assertThat(seekBarView.getVisibility()).isEqualTo(View.VISIBLE)
@@ -89,7 +85,7 @@
@Test
fun seekBarProgress() {
// WHEN seek bar progress is about half
- val data = SeekBarViewModel.Progress(true, true, 3000, 120000, -1)
+ val data = SeekBarViewModel.Progress(true, true, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is visible
assertThat(seekBarView.progress).isEqualTo(100)
@@ -102,7 +98,7 @@
fun seekBarDisabledWhenSeekNotAvailable() {
// WHEN seek is not available
val isSeekAvailable = false
- val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000, -1)
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is not enabled
assertThat(seekBarView.isEnabled()).isFalse()
@@ -112,20 +108,9 @@
fun seekBarEnabledWhenSeekNotAvailable() {
// WHEN seek is available
val isSeekAvailable = true
- val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000, -1)
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is not enabled
assertThat(seekBarView.isEnabled()).isTrue()
}
-
- @Test
- fun seekBarColor() {
- // WHEN data included color
- val data = SeekBarViewModel.Progress(true, true, 3000, 120000, Color.RED)
- observer.onChanged(data)
- // THEN seek bar is colored
- val red = ColorStateList.valueOf(Color.RED)
- assertThat(elapsedTimeView.getTextColors()).isEqualTo(red)
- assertThat(totalTimeView.getTextColors()).isEqualTo(red)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index cde575d..1bbf24f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.graphics.Color
import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.PlaybackState
@@ -80,12 +79,6 @@
}
@Test
- fun updateColor() {
- viewModel.updateController(mockController, Color.RED)
- assertThat(viewModel.progress.value!!.color).isEqualTo(Color.RED)
- }
-
- @Test
fun updateDurationWithPlayback() {
// GIVEN that the duration is contained within the metadata
val duration = 12000L
@@ -101,7 +94,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN the duration is extracted
assertThat(viewModel.progress.value!!.duration).isEqualTo(duration)
assertThat(viewModel.progress.value!!.enabled).isTrue()
@@ -117,7 +110,7 @@
}
whenever(mockController.getMetadata()).thenReturn(metadata)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN the duration is extracted
assertThat(viewModel.progress.value!!.duration).isEqualTo(duration)
assertThat(viewModel.progress.value!!.enabled).isFalse()
@@ -139,7 +132,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN the seek bar is disabled
assertThat(viewModel.progress.value!!.enabled).isFalse()
}
@@ -160,7 +153,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN the seek bar is disabled
assertThat(viewModel.progress.value!!.enabled).isFalse()
}
@@ -175,7 +168,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN elapsed time is captured
assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(200.toInt())
}
@@ -189,7 +182,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN seek is available
assertThat(viewModel.progress.value!!.seekAvailable).isTrue()
}
@@ -203,7 +196,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN seek is not available
assertThat(viewModel.progress.value!!.seekAvailable).isFalse()
}
@@ -211,7 +204,7 @@
@Test
fun handleSeek() {
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN user input is dispatched
val pos = 42L
viewModel.onSeek(pos)
@@ -223,7 +216,7 @@
@Test
fun handleProgressChangedUser() {
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN user starts dragging the seek bar
val pos = 42
viewModel.seekBarListener.onProgressChanged(SeekBar(context), pos, true)
@@ -235,7 +228,7 @@
@Test
fun handleProgressChangedOther() {
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN user starts dragging the seek bar
val pos = 42
viewModel.seekBarListener.onProgressChanged(SeekBar(context), pos, false)
@@ -247,7 +240,7 @@
@Test
fun handleStartTrackingTouch() {
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN user starts dragging the seek bar
val pos = 42
val bar = SeekBar(context).apply {
@@ -262,7 +255,7 @@
@Test
fun handleStopTrackingTouch() {
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN user ends drag
val pos = 42
val bar = SeekBar(context).apply {
@@ -283,7 +276,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN a task is queued
assertThat(fakeExecutor.numPending()).isEqualTo(1)
}
@@ -297,7 +290,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN an update task is not queued
assertThat(fakeExecutor.numPending()).isEqualTo(0)
}
@@ -317,7 +310,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN an update task is queued
assertThat(fakeExecutor.numPending()).isEqualTo(1)
}
@@ -337,7 +330,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// THEN an update task is not queued
assertThat(fakeExecutor.numPending()).isEqualTo(0)
}
@@ -350,7 +343,7 @@
build()
}
whenever(mockController.getPlaybackState()).thenReturn(state)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN the next task runs
with(fakeExecutor) {
advanceClockToNext()
@@ -361,25 +354,6 @@
}
@Test
- fun taskUpdatesProgress() {
- // GIVEN that the PlaybackState contins the initial position
- val initialPosition = 0L
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, initialPosition, 1f)
- build()
- }
- whenever(mockController.getPlaybackState()).thenReturn(state)
- viewModel.updateController(mockController, Color.RED)
- // WHEN the task runs
- with(fakeExecutor) {
- advanceClockToNext()
- runAllReady()
- }
- // THEN elapsed time has increased
- assertThat(viewModel.progress.value!!.elapsedTime).isGreaterThan(initialPosition.toInt())
- }
-
- @Test
fun startListeningQueuesPollTask() {
// GIVEN not listening
viewModel.listening = false
@@ -393,7 +367,7 @@
build()
}
whenever(mockController.getPlaybackState()).thenReturn(state)
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN start listening
viewModel.listening = true
// THEN an update task is queued
@@ -415,7 +389,7 @@
}
whenever(mockController.getPlaybackState()).thenReturn(state)
// AND the controller has been updated
- viewModel.updateController(mockController, Color.RED)
+ viewModel.updateController(mockController)
// WHEN the controller is cleared on the event when the session is destroyed
viewModel.clearController()
with(fakeExecutor) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
index 7211254..601fad6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
@@ -65,9 +65,6 @@
private IActivityManager mActivityManager;
@Mock
- private IActivityTaskManager mIActivityTaskManager;
-
- @Mock
private PipMenuActivityController mPipMenuActivityController;
@Mock
@@ -101,7 +98,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
- mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mIActivityTaskManager,
+ mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
mPipSnapAlgorithm);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index 9d35e53..05b31c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -25,6 +25,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -37,16 +39,18 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.statusbar.policy.SecurityController;
import org.junit.Before;
import org.junit.Test;
@@ -58,7 +62,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
-import java.util.concurrent.Executor;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -86,9 +89,7 @@
@Mock
private QSTileView mQSTileView;
@Mock
- private Executor mForegroundExecutor;
- @Mock
- private DelayableExecutor mBackgroundExecutor;
+ private MediaHost mMediaHost;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@Mock
@@ -100,14 +101,19 @@
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
-
mTestableLooper = TestableLooper.get(this);
+
+ // Dependencies for QSSecurityFooter
+ mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
+ mDependency.injectMockDependency(SecurityController.class);
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mContext.addMockSystemService(Context.USER_SERVICE, mock(UserManager.class));
+
mUiEventLogger = new UiEventLoggerFake();
mTestableLooper.runWithLooper(() -> {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
- mQSLogger, mForegroundExecutor, mBackgroundExecutor,
- mLocalBluetoothManager, mActivityStarter, mEntryManager, mUiEventLogger);
+ mQSLogger, mMediaHost, mUiEventLogger);
// Provides a parent with non-zero size for QSPanel
mParentView = new FrameLayout(mContext);
mParentView.addView(mQsPanel);
@@ -155,6 +161,9 @@
mQsPanel.setListening(true);
verify(mQSLogger).logAllTilesChangeListening(true, mQsPanel.getDumpableTag(), "dnd");
+
+ mQsPanel.setListening(false);
+ verify(mQSLogger).logAllTilesChangeListening(false, mQsPanel.getDumpableTag(), "dnd");
}
/* @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 72a6503..53ef866 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -23,10 +23,10 @@
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -41,6 +41,7 @@
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -50,10 +51,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tiles.HotspotTile;
-import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -63,6 +60,7 @@
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -73,6 +71,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class TileQueryHelperTest extends SysuiTestCase {
private static final String CURRENT_TILES = "wifi,dnd,nfc";
private static final String ONLY_STOCK_TILES = "wifi,dnd";
@@ -99,8 +98,6 @@
private QSTileHost mQSTileHost;
@Mock
private PackageManager mPackageManager;
- @Mock
- private QSLogger mQSLogger;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -112,8 +109,8 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+
mContext.setMockPackageManager(mPackageManager);
- when(mQSTileHost.getQSLogger()).thenReturn(mQSLogger);
mState = new QSTile.State();
doAnswer(invocation -> {
@@ -279,11 +276,10 @@
}
@Test
- public void testQueryTiles_notAvailableDestroyed_isNotNullSpec() {
- HotspotController mockHC = mock(HotspotController.class);
- DataSaverController mockDSC = mock(DataSaverController.class);
- when(mockHC.isHotspotSupported()).thenReturn(false);
- HotspotTile t = new HotspotTile(mQSTileHost, mockHC, mockDSC);
+ public void testQueryTiles_notAvailableDestroyed_tileSpecIsSet() {
+ Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null);
+
+ QSTile t = mock(QSTile.class);
when(mQSTileHost.createTile("hotspot")).thenReturn(t);
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
@@ -292,6 +288,8 @@
mTileQueryHelper.queryTiles(mQSTileHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
- verify(mQSLogger).logTileDestroyed(eq("hotspot"), anyString());
+ InOrder verifier = inOrder(t);
+ verifier.verify(t).setTileSpec("hotspot");
+ verifier.verify(t).destroy();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index cffcabb..63e6e8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -410,11 +410,12 @@
Bundle bundle = new Bundle();
String packageName = "test";
final long operationId = 1;
+ final int sysUiSessionId = 2;
mCommandQueue.showAuthenticationDialog(bundle, null /* receiver */, 1, true, 3,
- packageName, operationId);
+ packageName, operationId, sysUiSessionId);
waitForIdleSync();
verify(mCallbacks).showAuthenticationDialog(eq(bundle), eq(null), eq(1), eq(true), eq(3),
- eq(packageName), eq(operationId));
+ eq(packageName), eq(operationId), eq(sysUiSessionId));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index d124bad..a24fa84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -20,9 +20,9 @@
import static android.content.Intent.ACTION_USER_SWITCHED;
import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 1117646..5a7dea4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -82,7 +82,8 @@
() -> mock(StatusBar.class),
mStateController,
Handler.createAsync(Looper.myLooper()),
- mRemoteInputUriController);
+ mRemoteInputUriController,
+ mock(ActionClickLogger.class));
mEntry = new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_NAME)
.setOpPkg(TEST_PACKAGE_NAME)
@@ -256,17 +257,26 @@
private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
- TestableNotificationRemoteInputManager(Context context,
+ TestableNotificationRemoteInputManager(
+ Context context,
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
Lazy<StatusBar> statusBarLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
- RemoteInputUriController remoteInputUriController) {
- super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
- statusBarLazy, statusBarStateController, mainHandler,
- remoteInputUriController);
+ RemoteInputUriController remoteInputUriController,
+ ActionClickLogger actionClickLogger) {
+ super(
+ context,
+ lockscreenUserManager,
+ smartReplyController,
+ notificationEntryManager,
+ statusBarLazy,
+ statusBarStateController,
+ mainHandler,
+ remoteInputUriController,
+ actionClickLogger);
}
public void setUpWithPresenterForTest(Callback callback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 22dc080..79507e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -92,7 +92,8 @@
mNotificationEntryManager, () -> mock(StatusBar.class),
mStatusBarStateController,
Handler.createAsync(Looper.myLooper()),
- mRemoteInputUriController);
+ mRemoteInputUriController,
+ mock(ActionClickLogger.class));
mRemoteInputManager.setUpWithCallback(mCallback, mDelegate);
mNotification = new Notification.Builder(mContext, "")
.setSmallIcon(R.drawable.ic_person)
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 972357e..d583048 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
@@ -26,6 +26,7 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -93,6 +94,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -241,7 +243,7 @@
// Ensure that update callbacks happen in correct order
InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener);
order.verify(mEntryListener).onPreEntryUpdated(mEntry);
- order.verify(mPresenter).updateNotificationViews();
+ order.verify(mPresenter).updateNotificationViews(any());
order.verify(mEntryListener).onPostEntryUpdated(mEntry);
}
@@ -252,7 +254,7 @@
mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
- verify(mPresenter).updateNotificationViews();
+ verify(mPresenter).updateNotificationViews(any());
verify(mEntryListener).onEntryRemoved(
eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
verify(mRow).setRemoved();
@@ -261,6 +263,19 @@
}
@Test
+ public void testRemoveUninflatedNotification_removesNotificationFromAllNotifsList() {
+ // GIVEN an uninflated entry is added
+ mEntryManager.addNotification(mSbn, mRankingMap);
+ assertTrue(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
+
+ // WHEN the uninflated entry is removed
+ mEntryManager.performRemoveNotification(mSbn, UNDEFINED_DISMISS_REASON);
+
+ // THEN the entry is still removed from the allNotifications list
+ assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
+ }
+
+ @Test
public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -545,6 +560,15 @@
/* End annex */
+ private boolean entriesContainKey(Collection<NotificationEntry> entries, String key) {
+ for (NotificationEntry entry : entries) {
+ if (entry.getSbn().getKey().equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private Notification.Action createAction() {
return new Notification.Action.Builder(
Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 277ac24..595ba89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -93,7 +94,9 @@
.thenReturn(PackageManager.PERMISSION_GRANTED);
mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
mDependency.injectTestDependency(NotificationGroupManager.class,
- new NotificationGroupManager(mock(StatusBarStateController.class)));
+ new NotificationGroupManager(
+ mock(StatusBarStateController.class),
+ () -> mock(PeopleNotificationIdentifier.class)));
mDependency.injectMockDependency(ShadeController.class);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index b501a2e..8948fd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -49,12 +49,12 @@
manager!!.clearCache()
originalQsMediaPlayer = Settings.System.getInt(context.getContentResolver(),
"qs_media_player", 1)
- Settings.System.putInt(context.getContentResolver(), "qs_media_player", 0)
+ Settings.Global.putInt(context.getContentResolver(), "qs_media_player", 0)
}
@After
public fun teardown() {
- Settings.System.putInt(context.getContentResolver(), "qs_media_player",
+ Settings.Global.putInt(context.getContentResolver(), "qs_media_player",
originalQsMediaPlayer)
}
@@ -74,7 +74,7 @@
DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false)
assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled())
- assertTrue("Expecting 4 buckets when people filtering is enabled",
- manager!!.getNumberOfBuckets() == 4)
+ assertTrue("Expecting 5 buckets when people filtering is enabled",
+ manager!!.getNumberOfBuckets() == 5)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 3d06c57..ea1b498 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -108,7 +109,7 @@
public void testCallBackCalledScreenOn() {
mVisualStabilityManager.setPanelExpanded(true);
mVisualStabilityManager.setScreenOn(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
mVisualStabilityManager.setScreenOn(false);
verify(mCallback).onChangeAllowed();
}
@@ -117,7 +118,7 @@
public void testCallBackCalledPanelExpanded() {
mVisualStabilityManager.setPanelExpanded(true);
mVisualStabilityManager.setScreenOn(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
mVisualStabilityManager.setPanelExpanded(false);
verify(mCallback).onChangeAllowed();
}
@@ -126,7 +127,7 @@
public void testCallBackExactlyOnce() {
mVisualStabilityManager.setPanelExpanded(true);
mVisualStabilityManager.setScreenOn(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
mVisualStabilityManager.setScreenOn(false);
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.setScreenOn(false);
@@ -134,6 +135,17 @@
}
@Test
+ public void testCallBackCalledContinuouslyWhenRequested() {
+ mVisualStabilityManager.setPanelExpanded(true);
+ mVisualStabilityManager.setScreenOn(true);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, true /* persistent */);
+ mVisualStabilityManager.setScreenOn(false);
+ mVisualStabilityManager.setScreenOn(true);
+ mVisualStabilityManager.setScreenOn(false);
+ verify(mCallback, times(2)).onChangeAllowed();
+ }
+
+ @Test
public void testAddedCanReorder() {
mVisualStabilityManager.setPanelExpanded(true);
mVisualStabilityManager.setScreenOn(true);
@@ -188,7 +200,7 @@
@Test
public void testCallBackCalled_Pulsing() {
mVisualStabilityManager.setPulsing(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
mVisualStabilityManager.setPulsing(false);
verify(mCallback).onChangeAllowed();
}
@@ -198,7 +210,7 @@
// GIVEN having the panel open (which would block reordering)
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.setPanelExpanded(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
// WHEN we temprarily allow reordering
mVisualStabilityManager.temporarilyAllowReordering();
@@ -212,7 +224,7 @@
public void testTemporarilyAllowReorderingDoesntOverridePulsing() {
// GIVEN we are in a pulsing state
mVisualStabilityManager.setPulsing(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
// WHEN we temprarily allow reordering
mVisualStabilityManager.temporarilyAllowReordering();
@@ -227,7 +239,7 @@
// GIVEN having the panel open (which would block reordering)
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.setPanelExpanded(true);
- mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */);
// WHEN we temprarily allow reordering and then wait until the window expires
mVisualStabilityManager.temporarilyAllowReordering();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index b4cabfd..9f47f4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -21,6 +21,7 @@
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
+import android.os.SystemClock
import android.service.notification.NotificationListenerService.RankingMap
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -36,8 +37,8 @@
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Lazy
@@ -58,17 +59,19 @@
private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier
private lateinit var rankingManager: TestableNotificationRankingManager
private lateinit var sectionsManager: NotificationSectionsFeatureManager
+ private lateinit var notificationFilter: NotificationFilter
@Before
fun setup() {
personNotificationIdentifier =
mock(PeopleNotificationIdentifier::class.java)
sectionsManager = mock(NotificationSectionsFeatureManager::class.java)
+ notificationFilter = mock(NotificationFilter::class.java)
rankingManager = TestableNotificationRankingManager(
lazyMedia,
mock(NotificationGroupManager::class.java),
mock(HeadsUpManager::class.java),
- mock(NotificationFilter::class.java),
+ notificationFilter,
mock(NotificationEntryManagerLogger::class.java),
sectionsManager,
personNotificationIdentifier,
@@ -324,6 +327,32 @@
assertEquals(e.bucket, BUCKET_SILENT)
}
+ @Test
+ fun testFilter_resetsInitalizationTime() {
+ // GIVEN an entry that was initialized 1 second ago
+ val notif = Notification.Builder(mContext, "test") .build()
+
+ val e = NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(notif)
+ .setUser(mContext.user)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setOverrideGroupKey("")
+ .build()
+
+ e.setInitializationTime(SystemClock.elapsedRealtime() - 1000)
+ assertEquals(true, e.hasFinishedInitialization())
+
+ // WHEN we update ranking and filter out the notification entry
+ whenever(notificationFilter.shouldFilterOut(e)).thenReturn(true)
+ rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
+
+ // THEN the initialization time for the entry is reset
+ assertEquals(false, e.hasFinishedInitialization())
+ }
+
internal class TestableNotificationRankingManager(
mediaManager: Lazy<NotificationMediaManager>,
groupManager: NotificationGroupManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 3adc3d0..a93b54a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -19,8 +19,10 @@
import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpTree;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
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.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -33,6 +35,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
@@ -475,6 +478,28 @@
}
@Test
+ public void testFilter_resetsInitalizationTime() {
+ // GIVEN a NotifFilter that filters out a specific package
+ NotifFilter filter1 = spy(new PackageFilter(PACKAGE_1));
+ mListBuilder.addFinalizeFilter(filter1);
+
+ // GIVEN a notification that was initialized 1 second ago that will be filtered out
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(PACKAGE_1)
+ .setId(nextId(PACKAGE_1))
+ .setRank(nextRank())
+ .build();
+ entry.setInitializationTime(SystemClock.elapsedRealtime() - 1000);
+ assertTrue(entry.hasFinishedInitialization());
+
+ // WHEN the pipeline is kicked off
+ mReadyForBuildListener.onBuildList(Arrays.asList(entry));
+
+ // THEN the entry's initialization time is reset
+ assertFalse(entry.hasFinishedInitialization());
+ }
+
+ @Test
public void testNotifFiltersCanBePreempted() {
// GIVEN two notif filters
NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index d39b2c2..a3a46f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.logging;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
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 2894abb8..7dfead7 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
@@ -335,7 +335,7 @@
assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
// THEN we update the presenter
- verify(mPresenter).updateNotificationViews();
+ verify(mPresenter).updateNotificationViews(any());
}
@Test
@@ -364,7 +364,7 @@
verify(mEntryListener).onEntryReinflated(entry);
// THEN we update the presenter
- verify(mPresenter).updateNotificationViews();
+ verify(mPresenter).updateNotificationViews(any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 07f2085..b9eb4d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -115,7 +115,9 @@
dependency.injectMockDependency(BubbleController.class);
dependency.injectMockDependency(NotificationShadeWindowController.class);
mStatusBarStateController = mock(StatusBarStateController.class);
- mGroupManager = new NotificationGroupManager(mStatusBarStateController);
+ mGroupManager = new NotificationGroupManager(
+ mStatusBarStateController,
+ () -> mock(PeopleNotificationIdentifier.class));
mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController,
mock(KeyguardBypassController.class), mock(NotificationGroupManager.class),
mock(ConfigurationControllerImpl.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 1bfebfb..f21b1a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -356,6 +356,30 @@
}
@Test
+ public void testBindNotification_SetsOnClickListenerForSettings_mainText() {
+ final CountDownLatch latch = new CountDownLatch(1);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mChannelEditorDialogController,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ (View v, NotificationChannel c, int appUid) -> {
+ assertEquals(mNotificationChannel, c);
+ latch.countDown();
+ },
+ true,
+ false);
+
+ final View settingsButton = mInfo.findViewById(R.id.settings_link);
+ settingsButton.performClick();
+ // Verify that listener was triggered.
+ assertEquals(0, latch.getCount());
+ }
+
+ @Test
public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() {
mInfo.bindNotification(
mMockPackageManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 646bc96..3dc941a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -18,16 +18,20 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_FOREGROUND_SERVICE;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_HEADS_UP;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -42,12 +46,13 @@
import androidx.test.filters.SmallTest;
-import com.android.keyguard.KeyguardMediaPlayer;
import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -62,6 +67,9 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -74,27 +82,42 @@
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private ConfigurationController mConfigurationController;
@Mock private PeopleHubViewAdapter mPeopleHubAdapter;
- @Mock private KeyguardMediaPlayer mKeyguardMediaPlayer;
+ @Mock private KeyguardMediaController mKeyguardMediaController;
@Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
@Mock private NotificationRowComponent mNotificationRowComponent;
@Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
+ @Mock private NotificationSectionsLogger mLogger;
private NotificationSectionsManager mSectionsManager;
@Before
public void setUp() {
- when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(2);
- when(mNotificationRowComponent.getActivatableNotificationViewController()).thenReturn(
- mActivatableNotificationViewController
- );
+ when(mSectionsFeatureManager.getNumberOfBuckets()).thenAnswer(
+ invocation -> {
+ int count = 2;
+ if (mSectionsFeatureManager.isFilteringEnabled()) {
+ count = 5;
+ }
+ if (mSectionsFeatureManager.isMediaControlsEnabled()) {
+ if (!mSectionsFeatureManager.isFilteringEnabled()) {
+ count = 5;
+ } else {
+ count += 1;
+ }
+ }
+ return count;
+ });
+ when(mNotificationRowComponent.getActivatableNotificationViewController())
+ .thenReturn(mActivatableNotificationViewController);
mSectionsManager =
new NotificationSectionsManager(
mActivityStarterDelegate,
mStatusBarStateController,
mConfigurationController,
mPeopleHubAdapter,
- mKeyguardMediaPlayer,
- mSectionsFeatureManager
+ mKeyguardMediaController,
+ mSectionsFeatureManager,
+ mLogger
);
// Required in order for the header inflation to work properly
when(mNssl.generateLayoutParams(any(AttributeSet.class)))
@@ -102,6 +125,7 @@
mSectionsManager.initialize(mNssl, LayoutInflater.from(mContext));
when(mNssl.indexOfChild(any(View.class))).thenReturn(-1);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+
}
@Test(expected = IllegalStateException.class)
@@ -112,140 +136,152 @@
@Test
public void testInsertHeader() {
// GIVEN a stack with HI and LO rows but no section headers
- setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
+ setStackState(
+ ALERTING,
+ ALERTING,
+ ALERTING,
+ GENTLE);
// WHEN we update the section headers
mSectionsManager.updateSectionBoundaries();
// THEN a LO section header is added
- verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3);
+ verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 3);
}
@Test
public void testRemoveHeader() {
// GIVEN a stack that originally had a header between the HI and LO sections
- setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
+ setStackState(
+ ALERTING,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// WHEN the last LO row is replaced with a HI row
setStackState(
- ChildType.ALERTING,
- ChildType.ALERTING,
- ChildType.GENTLE_HEADER,
- ChildType.ALERTING);
+ ALERTING,
+ ALERTING,
+ GENTLE_HEADER,
+ ALERTING);
clearInvocations(mNssl);
mSectionsManager.updateSectionBoundaries();
// THEN the LO section header is removed
- verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
+ verify(mNssl).removeView(mSectionsManager.getSilentHeaderView());
}
@Test
public void testDoNothingIfHeaderAlreadyRemoved() {
// GIVEN a stack with only HI rows
- setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING);
+ setStackState(
+ ALERTING,
+ ALERTING,
+ ALERTING);
// WHEN we update the sections headers
mSectionsManager.updateSectionBoundaries();
// THEN we don't add any section headers
- verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt());
+ verify(mNssl, never()).addView(eq(mSectionsManager.getSilentHeaderView()), anyInt());
}
@Test
public void testMoveHeaderForward() {
// GIVEN a stack that originally had a header between the HI and LO sections
setStackState(
- ChildType.ALERTING,
- ChildType.ALERTING,
- ChildType.ALERTING,
- ChildType.GENTLE);
+ ALERTING,
+ ALERTING,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// WHEN the LO section moves forward
setStackState(
- ChildType.ALERTING,
- ChildType.ALERTING,
- ChildType.GENTLE,
- ChildType.GENTLE_HEADER,
- ChildType.GENTLE);
+ ALERTING,
+ ALERTING,
+ GENTLE,
+ GENTLE_HEADER,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// THEN the LO section header is also moved forward
- verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
+ verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 2);
}
@Test
public void testMoveHeaderBackward() {
// GIVEN a stack that originally had a header between the HI and LO sections
setStackState(
- ChildType.ALERTING,
- ChildType.GENTLE,
- ChildType.GENTLE,
- ChildType.GENTLE);
+ ALERTING,
+ GENTLE,
+ GENTLE,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// WHEN the LO section moves backward
setStackState(
- ChildType.ALERTING,
- ChildType.GENTLE_HEADER,
- ChildType.ALERTING,
- ChildType.ALERTING,
- ChildType.GENTLE);
+ ALERTING,
+ GENTLE_HEADER,
+ ALERTING,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// THEN the LO section header is also moved backward (with appropriate index shifting)
- verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 3);
+ verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 3);
}
@Test
public void testHeaderRemovedFromTransientParent() {
// GIVEN a stack where the header is animating away
setStackState(
- ChildType.ALERTING,
- ChildType.GENTLE,
- ChildType.GENTLE,
- ChildType.GENTLE);
- mSectionsManager.updateSectionBoundaries();
- setStackState(
- ChildType.ALERTING,
- ChildType.GENTLE_HEADER);
+ ALERTING,
+ GENTLE_HEADER);
mSectionsManager.updateSectionBoundaries();
clearInvocations(mNssl);
ViewGroup transientParent = mock(ViewGroup.class);
- mSectionsManager.getGentleHeaderView().setTransientContainer(transientParent);
+ mSectionsManager.getSilentHeaderView().setTransientContainer(transientParent);
// WHEN the LO section reappears
setStackState(
- ChildType.ALERTING,
- ChildType.GENTLE);
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// THEN the header is first removed from the transient parent before being added to the
// NSSL.
- verify(transientParent).removeTransientView(mSectionsManager.getGentleHeaderView());
- verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 1);
+ verify(transientParent).removeTransientView(mSectionsManager.getSilentHeaderView());
+ verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 1);
}
@Test
public void testHeaderNotShownOnLockscreen() {
// GIVEN a stack of HI and LO notifs on the lockscreen
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
- setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
+ setStackState(
+ ALERTING,
+ ALERTING,
+ ALERTING,
+ GENTLE);
// WHEN we update the section headers
mSectionsManager.updateSectionBoundaries();
// Then the section header is not added
- verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt());
+ verify(mNssl, never()).addView(eq(mSectionsManager.getSilentHeaderView()), anyInt());
}
@Test
public void testHeaderShownWhenEnterLockscreen() {
// GIVEN a stack of HI and LO notifs on the lockscreen
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
- setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
+ setStackState(
+ ALERTING,
+ ALERTING,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
// WHEN we unlock
@@ -253,20 +289,23 @@
mSectionsManager.updateSectionBoundaries();
// Then the section header is added
- verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3);
+ verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 3);
}
@Test
public void testHeaderHiddenWhenEnterLockscreen() {
// GIVEN a stack of HI and LO notifs on the shade
- setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE);
+ setStackState(
+ ALERTING,
+ GENTLE_HEADER,
+ GENTLE);
// WHEN we go back to the keyguard
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
mSectionsManager.updateSectionBoundaries();
// Then the section header is removed
- verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
+ verify(mNssl).removeView(mSectionsManager.getSilentHeaderView());
}
@Test
@@ -274,13 +313,13 @@
enablePeopleFiltering();
setStackState(
- ChildType.GENTLE_HEADER,
- ChildType.PERSON,
- ChildType.ALERTING,
- ChildType.GENTLE);
+ GENTLE_HEADER,
+ PERSON,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
- verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
+ verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 2);
verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
}
@@ -290,12 +329,12 @@
enablePeopleFiltering();
setStackState(
- ChildType.PERSON,
- ChildType.ALERTING,
- ChildType.GENTLE);
+ PERSON,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
- verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 2);
+ verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 2);
verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
}
@@ -305,15 +344,15 @@
enablePeopleFiltering();
setStackState(
- ChildType.PEOPLE_HEADER,
- ChildType.ALERTING_HEADER,
- ChildType.GENTLE_HEADER,
- ChildType.PERSON,
- ChildType.ALERTING,
- ChildType.GENTLE);
+ PEOPLE_HEADER,
+ ALERTING_HEADER,
+ GENTLE_HEADER,
+ PERSON,
+ ALERTING,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
- verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 4);
+ verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 4);
verify(mNssl).changeViewPosition(mSectionsManager.getAlertingHeaderView(), 2);
verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
}
@@ -324,12 +363,11 @@
enablePeopleFiltering();
setStackState(
- ChildType.PEOPLE_HEADER,
- ChildType.ALERTING_HEADER,
- ChildType.ALERTING,
- ChildType.GENTLE_HEADER,
- ChildType.GENTLE
- );
+ PEOPLE_HEADER,
+ ALERTING_HEADER,
+ ALERTING,
+ GENTLE_HEADER,
+ GENTLE);
mSectionsManager.updateSectionBoundaries();
verify(mNssl, never()).removeView(mSectionsManager.getPeopleHeaderView());
@@ -337,11 +375,120 @@
}
@Test
+ public void testPeopleFiltering_AlertingHunWhilePeopleVisible() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ PEOPLE_HEADER,
+ ALERTING.headsUp(),
+ PERSON,
+ ALERTING_HEADER,
+ GENTLE_HEADER,
+ GENTLE
+ );
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.INCOMING_HEADER,
+ ChildType.HEADS_UP,
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON,
+ ChildType.GENTLE_HEADER,
+ ChildType.GENTLE
+ );
+ }
+
+ @Test
+ public void testPeopleFiltering_PersonHunWhileAlertingHunVisible() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ PERSON.headsUp(),
+ INCOMING_HEADER,
+ ALERTING.headsUp(),
+ PEOPLE_HEADER,
+ PERSON
+ );
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.INCOMING_HEADER,
+ ChildType.HEADS_UP,
+ ChildType.HEADS_UP,
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON
+ );
+ }
+
+ @Test
+ public void testPeopleFiltering_PersonHun() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ PERSON.headsUp(),
+ PEOPLE_HEADER,
+ PERSON
+ );
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON,
+ ChildType.PERSON
+ );
+ }
+
+ @Test
+ public void testPeopleFiltering_AlertingHunWhilePersonHunning() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ ALERTING.headsUp(),
+ PERSON.headsUp()
+ );
+ mSectionsManager.updateSectionBoundaries();
+ verifyMockStack(
+ ChildType.INCOMING_HEADER,
+ ChildType.HEADS_UP,
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON
+ );
+ }
+
+ @Test
+ public void testPeopleFiltering_Fsn() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ INCOMING_HEADER,
+ ALERTING.headsUp(),
+ PEOPLE_HEADER,
+ FSN,
+ PERSON,
+ ALERTING,
+ GENTLE
+ );
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.INCOMING_HEADER,
+ ChildType.HEADS_UP,
+ ChildType.FSN,
+ ChildType.PEOPLE_HEADER,
+ ChildType.PERSON,
+ ChildType.ALERTING_HEADER,
+ ChildType.ALERTING,
+ ChildType.GENTLE_HEADER,
+ ChildType.GENTLE
+ );
+ }
+
+ @Test
public void testMediaControls_AddWhenEnterKeyguard() {
enableMediaControls();
// GIVEN a stack that doesn't include media controls
- setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE);
+ setStackState(ALERTING, GENTLE_HEADER, GENTLE);
// WHEN we go back to the keyguard
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
@@ -356,69 +503,45 @@
enableMediaControls();
// GIVEN a stack that doesn't include media controls but includes HEADS_UP
- setStackState(ChildType.HEADS_UP, ChildType.ALERTING, ChildType.GENTLE_HEADER,
- ChildType.GENTLE);
+ setupMockStack(
+ ALERTING.headsUp(),
+ ALERTING,
+ GENTLE_HEADER,
+ GENTLE);
// WHEN we go back to the keyguard
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
mSectionsManager.updateSectionBoundaries();
- // Then the media controls are added after HEADS_UP
- verify(mNssl).addView(mSectionsManager.getMediaControlsView(), 1);
- }
-
- @Test
- public void testMediaControls_RemoveWhenExitKeyguard() {
- enableMediaControls();
-
- // GIVEN a stack with media controls
- setStackState(ChildType.MEDIA_CONTROLS, ChildType.ALERTING, ChildType.GENTLE_HEADER,
+ verifyMockStack(
+ ChildType.MEDIA_CONTROLS,
+ ChildType.ALERTING,
+ ChildType.ALERTING,
ChildType.GENTLE);
-
- // WHEN we leave the keyguard
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
- mSectionsManager.updateSectionBoundaries();
-
- // Then the media controls is removed
- verify(mNssl).removeView(mSectionsManager.getMediaControlsView());
- }
-
- @Test
- public void testMediaControls_RemoveWhenPullDownShade() {
- enableMediaControls();
-
- // GIVEN a stack with media controls
- setStackState(ChildType.MEDIA_CONTROLS, ChildType.ALERTING, ChildType.GENTLE_HEADER,
- ChildType.GENTLE);
-
- // WHEN we pull down the shade on the keyguard
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
- mSectionsManager.updateSectionBoundaries();
-
- // Then the media controls is removed
- verify(mNssl).removeView(mSectionsManager.getMediaControlsView());
}
private void enablePeopleFiltering() {
when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
- when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
}
private void enableMediaControls() {
when(mSectionsFeatureManager.isMediaControlsEnabled()).thenReturn(true);
- when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
}
private enum ChildType {
- MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP, PERSON, ALERTING,
- GENTLE, OTHER
+ INCOMING_HEADER, MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP,
+ FSN, PERSON, ALERTING, GENTLE, OTHER
}
- private void setStackState(ChildType... children) {
+ private void setStackState(StackEntry... children) {
when(mNssl.getChildCount()).thenReturn(children.length);
for (int i = 0; i < children.length; i++) {
View child;
- switch (children[i]) {
+ StackEntry entry = children[i];
+ switch (entry.mChildType) {
+ case INCOMING_HEADER:
+ child = mSectionsManager.getIncomingHeaderView();
+ break;
case MEDIA_CONTROLS:
child = mSectionsManager.getMediaControlsView();
break;
@@ -429,19 +552,19 @@
child = mSectionsManager.getAlertingHeaderView();
break;
case GENTLE_HEADER:
- child = mSectionsManager.getGentleHeaderView();
+ child = mSectionsManager.getSilentHeaderView();
break;
- case HEADS_UP:
- child = mockNotification(BUCKET_HEADS_UP);
+ case FSN:
+ child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsHeadsUp);
break;
case PERSON:
- child = mockNotification(BUCKET_PEOPLE);
+ child = mockNotification(BUCKET_PEOPLE, entry.mIsHeadsUp);
break;
case ALERTING:
- child = mockNotification(BUCKET_ALERTING);
+ child = mockNotification(BUCKET_ALERTING, entry.mIsHeadsUp);
break;
case GENTLE:
- child = mockNotification(BUCKET_SILENT);
+ child = mockNotification(BUCKET_SILENT, entry.mIsHeadsUp);
break;
case OTHER:
child = mock(View.class);
@@ -456,12 +579,183 @@
}
}
- private View mockNotification(int bucket) {
- ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
- RETURNS_DEEP_STUBS);
+ private View mockNotification(int bucket, boolean headsUp) {
+ ExpandableNotificationRow notifRow =
+ mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
- when(notifRow.getEntry().getBucket()).thenReturn(bucket);
when(notifRow.getParent()).thenReturn(mNssl);
+
+ NotificationEntry mockEntry = mock(NotificationEntry.class);
+ when(notifRow.getEntry()).thenReturn(mockEntry);
+
+ int[] bucketRef = new int[] { bucket };
+ when(mockEntry.getBucket()).thenAnswer(invocation -> bucketRef[0]);
+ doAnswer(invocation -> {
+ bucketRef[0] = invocation.getArgument(0);
+ return null;
+ }).when(mockEntry).setBucket(anyInt());
+
+ when(notifRow.isHeadsUp()).thenReturn(headsUp);
+ when(mockEntry.isRowHeadsUp()).thenReturn(headsUp);
return notifRow;
}
+
+ private void verifyMockStack(ChildType... expected) {
+ final List<ChildType> actual = new ArrayList<>();
+ int childCount = mNssl.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = mNssl.getChildAt(i);
+ if (child == mSectionsManager.getIncomingHeaderView()) {
+ actual.add(ChildType.INCOMING_HEADER);
+ continue;
+ }
+ if (child == mSectionsManager.getMediaControlsView()) {
+ actual.add(ChildType.MEDIA_CONTROLS);
+ continue;
+ }
+ if (child == mSectionsManager.getPeopleHeaderView()) {
+ actual.add(ChildType.PEOPLE_HEADER);
+ continue;
+ }
+ if (child == mSectionsManager.getAlertingHeaderView()) {
+ actual.add(ChildType.ALERTING_HEADER);
+ continue;
+ }
+ if (child == mSectionsManager.getSilentHeaderView()) {
+ actual.add(ChildType.GENTLE_HEADER);
+ continue;
+ }
+ if (child instanceof ExpandableNotificationRow) {
+ switch (((ExpandableNotificationRow) child).getEntry().getBucket()) {
+ case BUCKET_HEADS_UP:
+ actual.add(ChildType.HEADS_UP);
+ break;
+ case BUCKET_FOREGROUND_SERVICE:
+ actual.add(ChildType.FSN);
+ break;
+ case BUCKET_PEOPLE:
+ actual.add(ChildType.PERSON);
+ break;
+ case BUCKET_ALERTING:
+ actual.add(ChildType.ALERTING);
+ break;
+ case BUCKET_SILENT:
+ actual.add(ChildType.GENTLE);
+ break;
+ default:
+ actual.add(ChildType.OTHER);
+ break;
+ }
+ continue;
+ }
+ actual.add(ChildType.OTHER);
+ }
+ assertThat(actual).containsExactly((Object[]) expected).inOrder();
+ }
+
+ private void setupMockStack(StackEntry... entries) {
+ final List<View> children = new ArrayList<>();
+ when(mNssl.getChildCount()).thenAnswer(invocation -> children.size());
+ when(mNssl.getChildAt(anyInt()))
+ .thenAnswer(invocation -> children.get(invocation.getArgument(0)));
+ when(mNssl.indexOfChild(any()))
+ .thenAnswer(invocation -> children.indexOf(invocation.getArgument(0)));
+ doAnswer(invocation -> {
+ View child = invocation.getArgument(0);
+ int index = invocation.getArgument(1);
+ children.add(index, child);
+ return null;
+ }).when(mNssl).addView(any(), anyInt());
+ doAnswer(invocation -> {
+ View child = invocation.getArgument(0);
+ children.remove(child);
+ return null;
+ }).when(mNssl).removeView(any());
+ doAnswer(invocation -> {
+ View child = invocation.getArgument(0);
+ int newIndex = invocation.getArgument(1);
+ children.remove(child);
+ children.add(newIndex, child);
+ return null;
+ }).when(mNssl).changeViewPosition(any(), anyInt());
+ for (StackEntry entry : entries) {
+ View child;
+ switch (entry.mChildType) {
+ case INCOMING_HEADER:
+ child = mSectionsManager.getIncomingHeaderView();
+ break;
+ case MEDIA_CONTROLS:
+ child = mSectionsManager.getMediaControlsView();
+ break;
+ case PEOPLE_HEADER:
+ child = mSectionsManager.getPeopleHeaderView();
+ break;
+ case ALERTING_HEADER:
+ child = mSectionsManager.getAlertingHeaderView();
+ break;
+ case GENTLE_HEADER:
+ child = mSectionsManager.getSilentHeaderView();
+ break;
+ case FSN:
+ child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsHeadsUp);
+ break;
+ case PERSON:
+ child = mockNotification(BUCKET_PEOPLE, entry.mIsHeadsUp);
+ break;
+ case ALERTING:
+ child = mockNotification(BUCKET_ALERTING, entry.mIsHeadsUp);
+ break;
+ case GENTLE:
+ child = mockNotification(BUCKET_SILENT, entry.mIsHeadsUp);
+ break;
+ case OTHER:
+ child = mock(View.class);
+ when(child.getVisibility()).thenReturn(View.VISIBLE);
+ when(child.getParent()).thenReturn(mNssl);
+ break;
+ default:
+ throw new RuntimeException("Unknown ChildType: " + entry.mChildType);
+ }
+ children.add(child);
+ }
+ }
+
+ private static final StackEntry INCOMING_HEADER = new StackEntry(ChildType.INCOMING_HEADER);
+ private static final StackEntry MEDIA_CONTROLS = new StackEntry(ChildType.MEDIA_CONTROLS);
+ private static final StackEntry PEOPLE_HEADER = new StackEntry(ChildType.PEOPLE_HEADER);
+ private static final StackEntry ALERTING_HEADER = new StackEntry(ChildType.ALERTING_HEADER);
+ private static final StackEntry GENTLE_HEADER = new StackEntry(ChildType.GENTLE_HEADER);
+ private static final StackEntry FSN = new StackEntry(ChildType.FSN);
+ private static final StackEntry.Hunnable PERSON = new StackEntry.Hunnable(ChildType.PERSON);
+ private static final StackEntry.Hunnable ALERTING = new StackEntry.Hunnable(ChildType.ALERTING);
+ private static final StackEntry GENTLE = new StackEntry(ChildType.GENTLE);
+
+ private static class StackEntry {
+ final ChildType mChildType;
+ final boolean mIsHeadsUp;
+
+ StackEntry(ChildType childType) {
+ this(childType, false);
+ }
+
+ StackEntry(ChildType childType, boolean isHeadsUp) {
+ mChildType = childType;
+ mIsHeadsUp = isHeadsUp;
+ }
+
+ static class Hunnable extends StackEntry {
+
+ Hunnable(ChildType childType) {
+ super(childType, false);
+ }
+
+ Hunnable(ChildType childType, boolean isHeadsUp) {
+ super(childType, isHeadsUp);
+ }
+
+ public Hunnable headsUp() {
+ return new Hunnable(mChildType, true);
+ }
+ }
+ }
}
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 1cb4d89..c4bd1b2 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
@@ -37,6 +37,7 @@
import static org.mockito.Mockito.when;
import android.metrics.LogMaker;
+import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -152,7 +153,8 @@
NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
Settings.Secure.putInt(mContext.getContentResolver(),
NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
- Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED, 1);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED,
+ 1, UserHandle.USER_CURRENT);
// Inject dependencies before initializing the layout
mDependency.injectMockDependency(VisualStabilityManager.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 67f94130..885dff3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
@@ -87,7 +88,9 @@
when(mNotificationEntryManager.getPendingNotificationsIterator())
.thenReturn(mPendingEntries.values());
- mGroupManager = new NotificationGroupManager(mock(StatusBarStateController.class));
+ mGroupManager = new NotificationGroupManager(
+ mock(StatusBarStateController.class),
+ () -> mock(PeopleNotificationIdentifier.class));
mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
index 19ce1ea..5a6f74a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -33,6 +33,7 @@
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
@@ -63,7 +64,9 @@
}
private void initializeGroupManager() {
- mGroupManager = new NotificationGroupManager(mock(StatusBarStateController.class));
+ mGroupManager = new NotificationGroupManager(
+ mock(StatusBarStateController.class),
+ () -> mock(PeopleNotificationIdentifier.class));
mGroupManager.setHeadsUpManager(mHeadsUpManager);
}
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 57ef055..b5663d5 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
@@ -55,6 +55,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -172,6 +173,8 @@
@Mock
private ConfigurationController mConfigurationController;
@Mock
+ private MediaHierarchyManager mMediaHiearchyManager;
+ @Mock
private ConversationNotificationManager mConversationNotificationManager;
private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
@@ -228,7 +231,7 @@
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
- mConversationNotificationManager);
+ mConversationNotificationManager, mMediaHiearchyManager);
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
mNotificationShelf, mNotificationAreaController, mScrimController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
index 5320ecd..ca6c16f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -44,6 +48,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -62,6 +67,7 @@
@Mock private SysuiColorExtractor mColorExtractor;
@Mock ColorExtractor.GradientColors mGradientColors;
@Mock private DumpManager mDumpManager;
+ @Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters;
private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -121,4 +127,46 @@
mNotificationShadeWindowController.setBackgroundBlurRadius(0);
verify(mNotificationShadeWindowView).setVisibility(eq(View.INVISIBLE));
}
+
+ @Test
+ public void setBouncerShowing_isFocusable_whenNeedsInput() {
+ mNotificationShadeWindowController.setKeyguardNeedsInput(true);
+ clearInvocations(mWindowManager);
+ mNotificationShadeWindowController.setBouncerShowing(true);
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) == 0).isTrue();
+ assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) == 0).isTrue();
+ }
+
+ @Test
+ public void setKeyguardShowing_focusable_notAltFocusable_whenNeedsInput() {
+ mNotificationShadeWindowController.setKeyguardShowing(true);
+ clearInvocations(mWindowManager);
+ mNotificationShadeWindowController.setKeyguardNeedsInput(true);
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) == 0).isTrue();
+ assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) == 0).isTrue();
+ }
+
+ @Test
+ public void setPanelExpanded_notFocusable_altFocusable_whenPanelIsOpen() {
+ mNotificationShadeWindowController.setPanelExpanded(true);
+ clearInvocations(mWindowManager);
+ mNotificationShadeWindowController.setNotificationShadeFocusable(true);
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) == 0).isTrue();
+ assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) != 0).isTrue();
+ }
+
+ @Test
+ public void setKeyguardShowing_notFocusable_byDefault() {
+ mNotificationShadeWindowController.setKeyguardShowing(false);
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) != 0).isTrue();
+ assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) == 0).isTrue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index cc2d1c2..e04d25b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -83,6 +83,7 @@
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
+ @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Before
public void setUp() {
@@ -121,7 +122,7 @@
mNotificationPanelViewController,
mStatusBarViewFactory);
mController.setupExpandedStatusBar();
- mController.setService(mStatusBar);
+ mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index cd2c349..bf2bd38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -31,6 +31,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -73,7 +74,8 @@
mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
mock(NotificationGroupManager.class), mNotificationLockscreenUserManager,
mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
- mActivityStarter, mShadeController, new CommandQueue(mContext)));
+ mActivityStarter, mShadeController, new CommandQueue(mContext),
+ mock(ActionClickLogger.class)));
mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
index 05a4867..f83fbd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -55,6 +55,7 @@
MockitoAnnotations.initMocks(this);
mBatteryController = new BatteryControllerImpl(getContext(), mock(EnhancedEstimates.class),
mPowerManager, mBroadcastDispatcher, new Handler(), new Handler());
+ mBatteryController.init();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 399b5c2..3b27437 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
+import android.os.Handler;
import android.os.Looper;
import android.telephony.CellSignalStrength;
import android.telephony.ServiceState;
@@ -46,6 +47,7 @@
import org.mockito.Mockito;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -68,6 +70,28 @@
}
@Test
+ public void testServiceStateInitialState() throws Exception {
+ // Verify that NetworkControllerImpl pulls the service state from Telephony upon
+ // initialization rather than relying on the sticky behavior of ACTION_SERVICE_STATE
+
+ when(mServiceState.isEmergencyOnly()).thenReturn(true);
+ when(mMockTm.getServiceState()).thenReturn(mServiceState);
+ when(mMockSm.getCompleteActiveSubscriptionInfoList()).thenReturn(Collections.emptyList());
+
+ mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
+ mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
+ mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
+ mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd);
+ mNetworkController.registerListeners();
+
+ // Wait for the main looper to execute the previous command
+ Handler mainThreadHandler = new Handler(Looper.getMainLooper());
+ waitForIdleSync(mainThreadHandler);
+
+ verifyEmergencyOnly(true);
+ }
+
+ @Test
public void testNoSimsIconPresent() {
// No Subscriptions.
mNetworkController.mMobileSignalControllers.clear();
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index bfb6524..1ee017b 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -27,7 +27,7 @@
"androidx.annotation_annotation",
"netd_aidl_interface-V3-java",
"netlink-client",
- "networkstack-aidl-interfaces-unstable-java",
+ "networkstack-aidl-interfaces-java",
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"net-utils-framework-common",
@@ -51,6 +51,11 @@
cc_library {
name: "libtetherutilsjni",
sdk_version: "current",
+ apex_available: [
+ "//apex_available:platform", // Used by InProcessTethering
+ "com.android.tethering",
+ ],
+ min_sdk_version: "current",
srcs: [
"jni/android_net_util_TetheringUtils.cpp",
],
@@ -109,6 +114,8 @@
manifest: "AndroidManifest_InProcess.xml",
// InProcessTethering is a replacement for Tethering
overrides: ["Tethering"],
+ apex_available: ["com.android.tethering"],
+ min_sdk_version: "current",
}
// Updatable tethering packaged as an application
@@ -122,4 +129,5 @@
// The permission configuration *must* be included to ensure security of the device
required: ["NetworkPermissionConfig"],
apex_available: ["com.android.tethering"],
+ min_sdk_version: "current",
}
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
index 24df5f6..67097a7 100644
--- a/packages/Tethering/apex/Android.bp
+++ b/packages/Tethering/apex/Android.bp
@@ -17,7 +17,7 @@
apex {
name: "com.android.tethering",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "current",
java_libs: ["framework-tethering"],
apps: ["Tethering"],
manifest: "manifest.json",
@@ -36,3 +36,12 @@
name: "com.android.tethering.certificate",
certificate: "com.android.tethering",
}
+
+override_apex {
+ name: "com.android.tethering.inprocess",
+ base: "com.android.tethering",
+ package_name: "com.android.tethering.inprocess",
+ apps: [
+ "InProcessTethering",
+ ],
+}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 8ae1593..ae4bb3e 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -13,43 +13,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// AIDL interfaces between the core system and the tethering mainline module.
-aidl_interface {
- name: "tethering-aidl-interfaces",
- unstable: true,
- local_include_dir: "src",
- include_dirs: ["frameworks/base/core/java"], // For framework parcelables.
- srcs: [
- // @JavaOnlyStableParcelable aidl declarations must not be listed here, as this would cause
- // compilation to fail (b/148001843).
- "src/android/net/IIntResultListener.aidl",
- "src/android/net/ITetheringConnector.aidl",
- "src/android/net/ITetheringEventCallback.aidl",
- "src/android/net/TetheringCallbackStartedParcel.aidl",
- "src/android/net/TetheringConfigurationParcel.aidl",
- "src/android/net/TetheringRequestParcel.aidl",
- "src/android/net/TetherStatesParcel.aidl",
- ],
- backend: {
- ndk: {
- enabled: false,
- },
- cpp: {
- enabled: false,
- },
- },
-}
-
java_library {
name: "framework-tethering",
sdk_version: "module_current",
srcs: [
- "src/android/net/TetheredClient.java",
- "src/android/net/TetheringManager.java",
- "src/android/net/TetheringConstants.java",
- ],
- static_libs: [
- "tethering-aidl-interfaces-java",
+ ":framework-tethering-srcs",
],
jarjar_rules: "jarjar-rules.txt",
installable: true,
@@ -94,6 +62,15 @@
"framework-module-stubs-defaults-publicapi",
"framework-tethering-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-tethering.api.public.latest",
+ removed_api_file: ":framework-tethering-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-tethering.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -102,6 +79,15 @@
"framework-module-stubs-defaults-systemapi",
"framework-tethering-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-tethering.api.system.latest",
+ removed_api_file: ":framework-tethering-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-tethering.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -110,6 +96,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-tethering-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-tethering.api.module-lib.latest",
+ removed_api_file: ":framework-tethering-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-tethering.api.module-lib.latest",
+ },
+ },
}
droidstubs {
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 83c99d2..9269c6f 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -57,6 +57,12 @@
<item>"bt-pan"</item>
</string-array>
+ <!-- Use the BPF offload for tethering when the kernel has support. True by default.
+ If the device doesn't want to support tether BPF offload, this should be false.
+ Note that this setting could be overridden by device config.
+ -->
+ <bool translatable="false" name="config_tether_enable_bpf_offload">true</bool>
+
<!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
<bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
@@ -64,6 +70,13 @@
<string-array translatable="false" name="config_tether_dhcp_range">
</string-array>
+ <!-- Used to config periodic polls tether offload stats from tethering offload HAL to make the
+ data warnings work. 5000(ms) by default. If the device doesn't want to poll tether
+ offload stats, this should be -1. Note that this setting could be override by
+ runtime resource overlays.
+ -->
+ <integer translatable="false" name="config_tether_offload_poll_interval">5000</integer>
+
<!-- Array of ConnectivityManager.TYPE_{BLUETOOTH, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI,
WIFI} values allowable for tethering.
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 16ae8ad..4e2bb1e 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -23,7 +23,13 @@
<item type="array" name="config_tether_wifi_p2p_regexs"/>
<item type="array" name="config_tether_bluetooth_regexs"/>
<item type="array" name="config_tether_dhcp_range"/>
+ <!-- Use the BPF offload for tethering when the kernel has support. True by default.
+ If the device doesn't want to support tether BPF offload, this should be false.
+ Note that this setting could be overridden by device config.
+ -->
+ <item type="bool" name="config_tether_enable_bpf_offload"/>
<item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+ <item type="integer" name="config_tether_offload_poll_interval"/>
<item type="array" name="config_tether_upstream_types"/>
<item type="bool" name="config_tether_upstream_automatic"/>
<!-- Configuration values for tethering entitlement check -->
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 83727bc..d993306 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -227,6 +227,7 @@
private final int mInterfaceType;
private final LinkProperties mLinkProperties;
private final boolean mUsingLegacyDhcp;
+ private final boolean mUsingBpfOffload;
private final Dependencies mDeps;
@@ -302,9 +303,12 @@
private final IpNeighborMonitor mIpNeighborMonitor;
+ // TODO: Add a dependency object to pass the data members or variables from the tethering
+ // object. It helps to reduce the arguments of the constructor.
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
- INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
+ INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload,
+ Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNetd = netd;
@@ -314,6 +318,7 @@
mInterfaceType = interfaceType;
mLinkProperties = new LinkProperties();
mUsingLegacyDhcp = usingLegacyDhcp;
+ mUsingBpfOffload = usingBpfOffload;
mDeps = deps;
resetLinkProperties();
mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
@@ -321,7 +326,12 @@
mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog,
new MyNeighborEventConsumer());
- if (!mIpNeighborMonitor.start()) {
+
+ // IP neighbor monitor monitors the neighbor events for adding/removing offload
+ // forwarding rules per client. If BPF offload is not supported, don't start listening
+ // for neighbor events. See updateIpv6ForwardingRules, addIpv6ForwardingRule,
+ // removeIpv6ForwardingRule.
+ if (mUsingBpfOffload && !mIpNeighborMonitor.start()) {
mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName);
}
@@ -715,12 +725,12 @@
final String upstreamIface = v6only.getInterfaceName();
params = new RaParams();
- // We advertise an mtu lower by 16, which is the closest multiple of 8 >= 14,
- // the ethernet header size. This makes kernel ebpf tethering offload happy.
- // This hack should be reverted once we have the kernel fixed up.
+ // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest
+ // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering
+ // offload happy. This hack should be reverted once we have the kernel fixed up.
// Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu)
// see RouterAdvertisementDaemon.java putMtu()
- params.mtu = v6only.getMtu() - 16;
+ params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu();
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface);
@@ -844,6 +854,11 @@
}
private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
+ // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
+ // offload is disabled. Add this check just in case.
+ // TODO: Perhaps remove this protection check.
+ if (!mUsingBpfOffload) return;
+
try {
mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
mIpv6ForwardingRules.put(rule.address, rule);
@@ -853,6 +868,11 @@
}
private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
+ // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
+ // offload is disabled. Add this check just in case.
+ // TODO: Perhaps remove this protection check.
+ if (!mUsingBpfOffload) return;
+
try {
mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
if (removeFromMap) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 049a9f6..3c6e8d8 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -37,6 +37,7 @@
import android.content.IntentFilter;
import android.net.util.SharedLog;
import android.os.Bundle;
+import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Parcel;
import android.os.PersistableBundle;
@@ -45,13 +46,12 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
-import android.util.ArraySet;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.StateMachine;
import java.io.PrintWriter;
+import java.util.BitSet;
/**
* Re-check tethering provisioning for enabled downstream tether types.
@@ -73,39 +73,39 @@
private final ComponentName mSilentProvisioningService;
private static final int MS_PER_HOUR = 60 * 60 * 1000;
+ private static final int DUMP_TIMEOUT = 10_000;
- // The ArraySet contains enabled downstream types, ex:
+ // The BitSet is the bit map of each enabled downstream types, ex:
// {@link TetheringManager.TETHERING_WIFI}
// {@link TetheringManager.TETHERING_USB}
// {@link TetheringManager.TETHERING_BLUETOOTH}
- private final ArraySet<Integer> mCurrentTethers;
+ private final BitSet mCurrentDownstreams;
+ private final BitSet mExemptedDownstreams;
private final Context mContext;
- private final int mPermissionChangeMessageCode;
private final SharedLog mLog;
private final SparseIntArray mEntitlementCacheValue;
private final Handler mHandler;
- private final StateMachine mTetherMasterSM;
// Key: TetheringManager.TETHERING_*(downstream).
// Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
- private final SparseIntArray mCellularPermitted;
+ private final SparseIntArray mCurrentEntitlementResults;
+ private final Runnable mPermissionChangeCallback;
private PendingIntent mProvisioningRecheckAlarm;
- private boolean mCellularUpstreamPermitted = true;
+ private boolean mLastCellularUpstreamPermitted = true;
private boolean mUsingCellularAsUpstream = false;
private boolean mNeedReRunProvisioningUi = false;
private OnUiEntitlementFailedListener mListener;
private TetheringConfigurationFetcher mFetcher;
- public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
- int permissionChangeMessageCode) {
-
+ public EntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
mContext = ctx;
mLog = log.forSubComponent(TAG);
- mCurrentTethers = new ArraySet<Integer>();
- mCellularPermitted = new SparseIntArray();
+ mCurrentDownstreams = new BitSet();
+ mExemptedDownstreams = new BitSet();
+ mCurrentEntitlementResults = new SparseIntArray();
mEntitlementCacheValue = new SparseIntArray();
- mTetherMasterSM = tetherMasterSM;
- mPermissionChangeMessageCode = permissionChangeMessageCode;
- mHandler = tetherMasterSM.getHandler();
+ mPermissionChangeCallback = callback;
+ mHandler = h;
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM),
null, mHandler);
mSilentProvisioningService = ComponentName.unflattenFromString(
@@ -144,13 +144,35 @@
* Check if cellular upstream is permitted.
*/
public boolean isCellularUpstreamPermitted() {
- // If provisioning is required and EntitlementManager don't know any downstream,
- // cellular upstream should not be allowed.
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (mCurrentTethers.size() == 0 && isTetherProvisioningRequired(config)) {
- return false;
- }
- return mCellularUpstreamPermitted;
+
+ return isCellularUpstreamPermitted(config);
+ }
+
+ private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) {
+ if (!isTetherProvisioningRequired(config)) return true;
+
+ // If provisioning is required and EntitlementManager doesn't know any downstreams, cellular
+ // upstream should not be enabled. Enable cellular upstream for exempted downstreams only
+ // when there is no non-exempted downstream.
+ if (mCurrentDownstreams.isEmpty()) return !mExemptedDownstreams.isEmpty();
+
+ return mCurrentEntitlementResults.indexOfValue(TETHER_ERROR_NO_ERROR) > -1;
+ }
+
+ /**
+ * Set exempted downstream type. If there is only exempted downstream type active,
+ * corresponding entitlement check will not be run and cellular upstream will be permitted
+ * by default. If a privileged app enables tethering without a provisioning check, and then
+ * another app enables tethering of the same type but does not disable the provisioning check,
+ * then the downstream immediately loses exempt status and a provisioning check is run.
+ * If any non-exempted downstream type is active, the cellular upstream will be gated by the
+ * result of entitlement check from non-exempted downstreams. If entitlement check is still
+ * in progress on non-exempt downstreams, ceullar upstream would default be disabled. When any
+ * non-exempted downstream gets positive entitlement result, ceullar upstream will be enabled.
+ */
+ public void setExemptedDownstreamType(final int type) {
+ mExemptedDownstreams.set(type, true);
}
/**
@@ -164,29 +186,24 @@
public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) {
if (!isValidDownstreamType(downstreamType)) return;
- if (!mCurrentTethers.contains(downstreamType)) mCurrentTethers.add(downstreamType);
+ mCurrentDownstreams.set(downstreamType, true);
+
+ mExemptedDownstreams.set(downstreamType, false);
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (isTetherProvisioningRequired(config)) {
- // If provisioning is required and the result is not available yet,
- // cellular upstream should not be allowed.
- if (mCellularPermitted.size() == 0) {
- mCellularUpstreamPermitted = false;
- }
- // If upstream is not cellular, provisioning app would not be launched
- // till upstream change to cellular.
- if (mUsingCellularAsUpstream) {
- if (showProvisioningUi) {
- runUiTetherProvisioning(downstreamType, config.activeDataSubId);
- } else {
- runSilentTetherProvisioning(downstreamType, config.activeDataSubId);
- }
- mNeedReRunProvisioningUi = false;
+ if (!isTetherProvisioningRequired(config)) return;
+
+ // If upstream is not cellular, provisioning app would not be launched
+ // till upstream change to cellular.
+ if (mUsingCellularAsUpstream) {
+ if (showProvisioningUi) {
+ runUiTetherProvisioning(downstreamType, config.activeDataSubId);
} else {
- mNeedReRunProvisioningUi |= showProvisioningUi;
+ runSilentTetherProvisioning(downstreamType, config.activeDataSubId);
}
+ mNeedReRunProvisioningUi = false;
} else {
- mCellularUpstreamPermitted = true;
+ mNeedReRunProvisioningUi |= showProvisioningUi;
}
}
@@ -195,14 +212,15 @@
*
* @param type tethering type from TetheringManager.TETHERING_{@code *}
*/
- public void stopProvisioningIfNeeded(int type) {
- if (!isValidDownstreamType(type)) return;
+ public void stopProvisioningIfNeeded(int downstreamType) {
+ if (!isValidDownstreamType(downstreamType)) return;
- mCurrentTethers.remove(type);
+ mCurrentDownstreams.set(downstreamType, false);
// There are lurking bugs where the notion of "provisioning required" or
// "tethering supported" may change without without tethering being notified properly.
// Remove the mapping all the time no matter provisioning is required or not.
- removeDownstreamMapping(type);
+ removeDownstreamMapping(downstreamType);
+ mExemptedDownstreams.set(downstreamType, false);
}
/**
@@ -213,7 +231,7 @@
public void notifyUpstream(boolean isCellular) {
if (DBG) {
mLog.i("notifyUpstream: " + isCellular
- + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted
+ + ", mLastCellularUpstreamPermitted: " + mLastCellularUpstreamPermitted
+ ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
}
mUsingCellularAsUpstream = isCellular;
@@ -231,7 +249,7 @@
}
private void maybeRunProvisioning(final TetheringConfiguration config) {
- if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) {
+ if (mCurrentDownstreams.isEmpty() || !isTetherProvisioningRequired(config)) {
return;
}
@@ -239,8 +257,9 @@
// are allowed. Therefore even if the silent check here ends in a failure and the UI later
// yields success, then the downstream that got a failure will re-evaluate as a result of
// the change and get the new correct value.
- for (Integer downstream : mCurrentTethers) {
- if (mCellularPermitted.indexOfKey(downstream) < 0) {
+ for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0;
+ downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) {
+ if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
if (mNeedReRunProvisioningUi) {
mNeedReRunProvisioningUi = false;
runUiTetherProvisioning(downstream, config.activeDataSubId);
@@ -286,7 +305,7 @@
mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
}
mEntitlementCacheValue.clear();
- mCellularPermitted.clear();
+ mCurrentEntitlementResults.clear();
// TODO: refine provisioning check to isTetherProvisioningRequired() ??
if (!config.hasMobileHotspotProvisionApp()
@@ -410,26 +429,25 @@
}
private void evaluateCellularPermission(final TetheringConfiguration config) {
- final boolean oldPermitted = mCellularUpstreamPermitted;
- mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config)
- || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
+ final boolean permitted = isCellularUpstreamPermitted(config);
if (DBG) {
- mLog.i("Cellular permission change from " + oldPermitted
- + " to " + mCellularUpstreamPermitted);
+ mLog.i("Cellular permission change from " + mLastCellularUpstreamPermitted
+ + " to " + permitted);
}
- if (mCellularUpstreamPermitted != oldPermitted) {
- mLog.log("Cellular permission change: " + mCellularUpstreamPermitted);
- mTetherMasterSM.sendMessage(mPermissionChangeMessageCode);
+ if (mLastCellularUpstreamPermitted != permitted) {
+ mLog.log("Cellular permission change: " + permitted);
+ mPermissionChangeCallback.run();
}
// Only schedule periodic re-check when tether is provisioned
// and the result is ok.
- if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) {
+ if (permitted && mCurrentEntitlementResults.size() > 0) {
scheduleProvisioningRechecks(config);
} else {
cancelTetherProvisioningRechecks();
}
+ mLastCellularUpstreamPermitted = permitted;
}
/**
@@ -441,10 +459,10 @@
*/
protected void addDownstreamMapping(int type, int resultCode) {
mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode
- + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
- if (!mCurrentTethers.contains(type)) return;
+ + " ,TetherTypeRequested: " + mCurrentDownstreams.get(type));
+ if (!mCurrentDownstreams.get(type)) return;
- mCellularPermitted.put(type, resultCode);
+ mCurrentEntitlementResults.put(type, resultCode);
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
evaluateCellularPermission(config);
}
@@ -455,7 +473,7 @@
*/
protected void removeDownstreamMapping(int type) {
mLog.i("removeDownstreamMapping: " + type);
- mCellularPermitted.delete(type);
+ mCurrentEntitlementResults.delete(type);
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
evaluateCellularPermission(config);
}
@@ -488,18 +506,33 @@
* @param pw {@link PrintWriter} is used to print formatted
*/
public void dump(PrintWriter pw) {
- pw.print("mCellularUpstreamPermitted: ");
- pw.println(mCellularUpstreamPermitted);
- for (Integer type : mCurrentTethers) {
- pw.print("Type: ");
- pw.print(typeString(type));
- if (mCellularPermitted.indexOfKey(type) > -1) {
- pw.print(", Value: ");
- pw.println(errorString(mCellularPermitted.get(type)));
- } else {
- pw.println(", Value: empty");
+ final ConditionVariable mWaiting = new ConditionVariable();
+ mHandler.post(() -> {
+ pw.print("isCellularUpstreamPermitted: ");
+ pw.println(isCellularUpstreamPermitted());
+ for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0;
+ type = mCurrentDownstreams.nextSetBit(type + 1)) {
+ pw.print("Type: ");
+ pw.print(typeString(type));
+ if (mCurrentEntitlementResults.indexOfKey(type) > -1) {
+ pw.print(", Value: ");
+ pw.println(errorString(mCurrentEntitlementResults.get(type)));
+ } else {
+ pw.println(", Value: empty");
+ }
}
+ mWaiting.open();
+ });
+ if (!mWaiting.block(DUMP_TIMEOUT)) {
+ pw.println("... dump timed out after " + DUMP_TIMEOUT + "ms");
}
+ pw.print("Exempted: [");
+ for (int type = mExemptedDownstreams.nextSetBit(0); type >= 0;
+ type = mExemptedDownstreams.nextSetBit(type + 1)) {
+ pw.print(typeString(type));
+ pw.print(", ");
+ }
+ pw.println("]");
}
private static String typeString(int type) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
index 1817f35..88c77b0 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
@@ -26,6 +26,8 @@
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.usage.NetworkStatsManager;
@@ -77,7 +79,6 @@
private static final boolean DBG = false;
private static final String ANYIP = "0.0.0.0";
private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
- private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000;
@VisibleForTesting
enum StatsType {
@@ -134,11 +135,9 @@
private final Dependencies mDeps;
// TODO: Put more parameters in constructor into dependency object.
- static class Dependencies {
- int getPerformPollInterval() {
- // TODO: Consider make this configurable.
- return DEFAULT_PERFORM_POLL_INTERVAL_MS;
- }
+ interface Dependencies {
+ @NonNull
+ TetheringConfiguration getTetherConfig();
}
public OffloadController(Handler h, OffloadHardwareInterface hwi,
@@ -452,12 +451,16 @@
if (mHandler.hasCallbacks(mScheduledPollingTask)) {
mHandler.removeCallbacks(mScheduledPollingTask);
}
- mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval());
+ mHandler.postDelayed(mScheduledPollingTask,
+ mDeps.getTetherConfig().getOffloadPollInterval());
}
private boolean isPollingStatsNeeded() {
return started() && mRemainingAlertQuota > 0
- && !TextUtils.isEmpty(currentUpstreamInterface());
+ && !TextUtils.isEmpty(currentUpstreamInterface())
+ && mDeps.getTetherConfig() != null
+ && mDeps.getTetherConfig().getOffloadPollInterval()
+ >= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
}
private boolean maybeUpdateDataLimit(String iface) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index 293f8ea..fe92204 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -66,6 +66,7 @@
private final Handler mHandler;
private final SharedLog mLog;
+ private final Dependencies mDeps;
private IOffloadControl mOffloadControl;
private TetheringOffloadCallback mTetheringOffloadCallback;
private ControlCallback mControlCallback;
@@ -126,8 +127,76 @@
}
public OffloadHardwareInterface(Handler h, SharedLog log) {
+ this(h, log, new Dependencies(log));
+ }
+
+ OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) {
mHandler = h;
mLog = log.forSubComponent(TAG);
+ mDeps = deps;
+ }
+
+ /** Capture OffloadHardwareInterface dependencies, for injection. */
+ static class Dependencies {
+ private final SharedLog mLog;
+
+ Dependencies(SharedLog log) {
+ mLog = log;
+ }
+
+ public IOffloadConfig getOffloadConfig() {
+ try {
+ return IOffloadConfig.getService(true /*retry*/);
+ } catch (RemoteException | NoSuchElementException e) {
+ mLog.e("getIOffloadConfig error " + e);
+ return null;
+ }
+ }
+
+ public IOffloadControl getOffloadControl() {
+ try {
+ return IOffloadControl.getService(true /*retry*/);
+ } catch (RemoteException | NoSuchElementException e) {
+ mLog.e("tethering offload control not supported: " + e);
+ return null;
+ }
+ }
+
+ public NativeHandle createConntrackSocket(final int groups) {
+ final FileDescriptor fd;
+ try {
+ fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
+ } catch (ErrnoException e) {
+ mLog.e("Unable to create conntrack socket " + e);
+ return null;
+ }
+
+ final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
+ try {
+ Os.bind(fd, sockAddr);
+ } catch (ErrnoException | SocketException e) {
+ mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ie) {
+ // Nothing we can do here
+ }
+ return null;
+ }
+ try {
+ Os.connect(fd, sockAddr);
+ } catch (ErrnoException | SocketException e) {
+ mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ie) {
+ // Nothing we can do here
+ }
+ return null;
+ }
+
+ return new NativeHandle(fd, true);
+ }
}
/** Get default value indicating whether offload is supported. */
@@ -141,13 +210,7 @@
* share them with offload management process.
*/
public boolean initOffloadConfig() {
- IOffloadConfig offloadConfig;
- try {
- offloadConfig = IOffloadConfig.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
- mLog.e("getIOffloadConfig error " + e);
- return false;
- }
+ final IOffloadConfig offloadConfig = mDeps.getOffloadConfig();
if (offloadConfig == null) {
mLog.e("Could not find IOffloadConfig service");
return false;
@@ -159,11 +222,11 @@
//
// h2 provides a file descriptor bound to the following netlink groups
// (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
- final NativeHandle h1 = createConntrackSocket(
+ final NativeHandle h1 = mDeps.createConntrackSocket(
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
if (h1 == null) return false;
- final NativeHandle h2 = createConntrackSocket(
+ final NativeHandle h2 = mDeps.createConntrackSocket(
NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
if (h2 == null) {
closeFdInNativeHandle(h1);
@@ -198,53 +261,12 @@
}
}
- private NativeHandle createConntrackSocket(final int groups) {
- FileDescriptor fd;
- try {
- fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
- } catch (ErrnoException e) {
- mLog.e("Unable to create conntrack socket " + e);
- return null;
- }
-
- final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
- try {
- Os.bind(fd, sockAddr);
- } catch (ErrnoException | SocketException e) {
- mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ie) {
- // Nothing we can do here
- }
- return null;
- }
- try {
- Os.connect(fd, sockAddr);
- } catch (ErrnoException | SocketException e) {
- mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ie) {
- // Nothing we can do here
- }
- return null;
- }
-
- return new NativeHandle(fd, true);
- }
-
/** Initialize the tethering offload HAL. */
public boolean initOffloadControl(ControlCallback controlCb) {
mControlCallback = controlCb;
if (mOffloadControl == null) {
- try {
- mOffloadControl = IOffloadControl.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
- mLog.e("tethering offload control not supported: " + e);
- return false;
- }
+ mOffloadControl = mDeps.getOffloadControl();
if (mOffloadControl == null) {
mLog.e("tethering IOffloadControl.getService() returned null");
return false;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 0a95a5e..04ad43f 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -62,7 +62,6 @@
import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
-import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
@@ -110,8 +109,10 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -229,6 +230,7 @@
private final ConnectedClientsTracker mConnectedClientsTracker;
private final TetheringThreadExecutor mExecutor;
private final TetheringNotificationUpdater mNotificationUpdater;
+ private final UserManager mUserManager;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
// All the usage of mTetheringEventCallback should run in the same thread.
private ITetheringEventCallback mTetheringEventCallback = null;
@@ -268,12 +270,15 @@
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
mTetherMasterSM.start();
- final NetworkStatsManager statsManager =
- (NetworkStatsManager) mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
mHandler = mTetherMasterSM.getHandler();
- mOffloadController = new OffloadController(mHandler,
- mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(),
- statsManager, mLog, new OffloadController.Dependencies());
+ mOffloadController = mDeps.getOffloadController(mHandler, mLog,
+ new OffloadController.Dependencies() {
+
+ @Override
+ public TetheringConfiguration getTetherConfig() {
+ return mConfig;
+ }
+ });
mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new LinkedHashSet<>();
@@ -282,8 +287,9 @@
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
// EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
// permission is changed according to entitlement check result.
- mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
- TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED);
+ mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
+ () -> mTetherMasterSM.sendMessage(
+ TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
mLog.log("OBSERVED UiEnitlementFailed");
stopTethering(downstream);
@@ -302,23 +308,24 @@
mStateReceiver = new StateReceiver();
- final UserManager userManager = (UserManager) mContext.getSystemService(
- Context.USER_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(
- userManager, this, mNotificationUpdater);
+ mUserManager, this, mNotificationUpdater);
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
mNetdCallback = new NetdCallback();
// Load tethering configuration.
updateConfiguration();
+
+ startStateMachineUpdaters();
}
/**
* Start to register callbacks.
* Call this function when tethering is ready to handle callback events.
*/
- public void startStateMachineUpdaters() {
+ private void startStateMachineUpdaters() {
try {
mNetd.registerUnsolicitedEventListener(mNetdCallback);
} catch (RemoteException e) {
@@ -513,8 +520,12 @@
}
mActiveTetheringRequests.put(request.tetheringType, request);
- mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
- request.showProvisioningUi);
+ if (request.exemptFromEntitlementCheck) {
+ mEntitlementMgr.setExemptedDownstreamType(request.tetheringType);
+ } else {
+ mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
+ request.showProvisioningUi);
+ }
enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
});
}
@@ -772,7 +783,7 @@
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
- if (!mDeps.isTetheringSupported()) return;
+ if (!isTetheringSupported()) return;
final ArrayList<String> availableList = new ArrayList<>();
final ArrayList<String> tetherList = new ArrayList<>();
@@ -1013,14 +1024,14 @@
@VisibleForTesting
protected static class UserRestrictionActionListener {
- private final UserManager mUserManager;
+ private final UserManager mUserMgr;
private final Tethering mWrapper;
private final TetheringNotificationUpdater mNotificationUpdater;
public boolean mDisallowTethering;
public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
@NonNull TetheringNotificationUpdater updater) {
- mUserManager = um;
+ mUserMgr = um;
mWrapper = wrapper;
mNotificationUpdater = updater;
mDisallowTethering = false;
@@ -1030,7 +1041,7 @@
// getUserRestrictions gets restriction for this process' user, which is the primary
// user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
// user. See UserManager.DISALLOW_CONFIG_TETHERING.
- final Bundle restrictions = mUserManager.getUserRestrictions();
+ final Bundle restrictions = mUserMgr.getUserRestrictions();
final boolean newlyDisallowed =
restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
final boolean prevDisallowed = mDisallowTethering;
@@ -1981,7 +1992,7 @@
mHandler.post(() -> {
mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
- parcel.tetheringSupported = mDeps.isTetheringSupported();
+ parcel.tetheringSupported = isTetheringSupported();
parcel.upstreamNetwork = mTetherUpstream;
parcel.config = mConfig.toStableParcelable();
parcel.states =
@@ -2104,6 +2115,20 @@
}
}
+ // if ro.tether.denied = true we default to no tethering
+ // gservices could set the secure setting to 1 though to enable it on a build where it
+ // had previously been turned off.
+ boolean isTetheringSupported() {
+ final int defaultVal =
+ SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+ final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
+ final boolean tetherEnabledInSettings = tetherSupported
+ && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
+
+ return tetherEnabledInSettings && hasTetherableConfiguration();
+ }
+
void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
@@ -2289,7 +2314,7 @@
final TetherState tetherState = new TetherState(
new IpServer(iface, mLooper, interfaceType, mLog, mNetd,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
- mDeps.getIpServerDependencies()));
+ mConfig.enableBpfOffload, mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index aeac437..48a600d 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -73,11 +73,23 @@
private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
/**
+ * Override enabling BPF offload configuration for tethering.
+ */
+ public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD =
+ "override_tether_enable_bpf_offload";
+
+ /**
* Use the old dnsmasq DHCP server for tethering instead of the framework implementation.
*/
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
"tether_enable_legacy_dhcp_server";
+ /**
+ * Default value that used to periodic polls tether offload stats from tethering offload HAL
+ * to make the data warnings work.
+ */
+ public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000;
+
public final String[] tetherableUsbRegexs;
public final String[] tetherableWifiRegexs;
public final String[] tetherableWifiP2pRegexs;
@@ -89,6 +101,8 @@
public final String[] legacyDhcpRanges;
public final String[] defaultIPv4DNS;
public final boolean enableLegacyDhcpServer;
+ // TODO: Add to TetheringConfigurationParcel if required.
+ public final boolean enableBpfOffload;
public final String[] provisioningApp;
public final String provisioningAppNoUi;
@@ -96,6 +110,8 @@
public final int activeDataSubId;
+ private final int mOffloadPollInterval;
+
public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
@@ -116,11 +132,12 @@
isDunRequired = checkDunRequired(ctx);
chooseUpstreamAutomatically = getResourceBoolean(
- res, R.bool.config_tether_upstream_automatic);
+ res, R.bool.config_tether_upstream_automatic, false /** defaultValue */);
preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
legacyDhcpRanges = getLegacyDhcpRanges(res);
defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
+ enableBpfOffload = getEnableBpfOffload(res);
enableLegacyDhcpServer = getEnableLegacyDhcpServer(res);
provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app);
@@ -129,6 +146,10 @@
R.integer.config_mobile_hotspot_provision_check_period,
0 /* No periodic re-check */);
+ mOffloadPollInterval = getResourceInteger(res,
+ R.integer.config_tether_offload_poll_interval,
+ DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+
configLog.log(toString());
}
@@ -189,10 +210,16 @@
dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges);
dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);
+ pw.print("offloadPollInterval: ");
+ pw.println(mOffloadPollInterval);
+
dumpStringArray(pw, "provisioningApp", provisioningApp);
pw.print("provisioningAppNoUi: ");
pw.println(provisioningAppNoUi);
+ pw.print("enableBpfOffload: ");
+ pw.println(enableBpfOffload);
+
pw.print("enableLegacyDhcpServer: ");
pw.println(enableLegacyDhcpServer);
}
@@ -208,10 +235,12 @@
makeString(tetherableBluetoothRegexs)));
sj.add(String.format("isDunRequired:%s", isDunRequired));
sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically));
+ sj.add(String.format("offloadPollInterval:%d", mOffloadPollInterval));
sj.add(String.format("preferredUpstreamIfaceTypes:%s",
toIntArray(preferredUpstreamIfaceTypes)));
sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi));
+ sj.add(String.format("enableBpfOffload:%s", enableBpfOffload));
sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer));
return String.format("TetheringConfiguration{%s}", sj.toString());
}
@@ -246,6 +275,10 @@
return (tm != null) ? tm.isTetheringApnRequired() : false;
}
+ public int getOffloadPollInterval() {
+ return mOffloadPollInterval;
+ }
+
private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types);
final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
@@ -312,11 +345,11 @@
}
}
- private static boolean getResourceBoolean(Resources res, int resId) {
+ private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) {
try {
return res.getBoolean(resId);
} catch (Resources.NotFoundException e404) {
- return false;
+ return defaultValue;
}
}
@@ -337,14 +370,36 @@
}
}
+ private boolean getEnableBpfOffload(final Resources res) {
+ // Get BPF offload config
+ // Priority 1: Device config
+ // Priority 2: Resource config
+ // Priority 3: Default value
+ final boolean defaultValue = getResourceBoolean(
+ res, R.bool.config_tether_enable_bpf_offload, true /** default value */);
+
+ return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue);
+ }
+
private boolean getEnableLegacyDhcpServer(final Resources res) {
- return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server)
- || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER);
+ return getResourceBoolean(
+ res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */)
+ || getDeviceConfigBoolean(
+ TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */);
+ }
+
+ private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) {
+ // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead
+ // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the
+ // returned boolean value comes from device config or default value (because of null
+ // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java.
+ final String value = getDeviceConfigProperty(name);
+ return value != null ? Boolean.parseBoolean(value) : defaultValue;
}
@VisibleForTesting
- protected boolean getDeviceConfigBoolean(final String name) {
- return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */);
+ protected String getDeviceConfigProperty(String name) {
+ return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name);
}
private Resources getResources(Context ctx, int subId) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index 9b54b5f..ce546c7 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -16,6 +16,7 @@
package com.android.networkstack.tethering;
+import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.net.INetd;
@@ -47,6 +48,19 @@
}
/**
+ * Get a reference to the offload controller to be used by tethering.
+ */
+ @NonNull
+ public OffloadController getOffloadController(@NonNull Handler h,
+ @NonNull SharedLog log, @NonNull OffloadController.Dependencies deps) {
+ final NetworkStatsManager statsManager =
+ (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE);
+ return new OffloadController(h, getOffloadHardwareInterface(h, log),
+ getContext().getContentResolver(), statsManager, log, deps);
+ }
+
+
+ /**
* Get a reference to the UpstreamNetworkMonitor to be used by tethering.
*/
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
@@ -82,9 +96,9 @@
/**
* Get a reference to the EntitlementManager to be used by tethering.
*/
- public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
- SharedLog log, int what) {
- return new EntitlementManager(ctx, target, log, what);
+ public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
+ return new EntitlementManager(ctx, h, log, callback);
}
/**
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 3ed2115..bf7fb04 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -16,6 +16,8 @@
package com.android.networkstack.tethering;
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static android.Manifest.permission.TETHER_PRIVILEGED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
@@ -38,15 +40,12 @@
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.ip.IpServer;
-import android.net.util.SharedLog;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SystemProperties;
-import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
@@ -66,21 +65,14 @@
public class TetheringService extends Service {
private static final String TAG = TetheringService.class.getSimpleName();
- private final SharedLog mLog = new SharedLog(TAG);
private TetheringConnector mConnector;
- private Context mContext;
- private TetheringDependencies mDeps;
- private Tethering mTethering;
- private UserManager mUserManager;
@Override
public void onCreate() {
- mLog.mark("onCreate");
- mDeps = getTetheringDependencies();
- mContext = mDeps.getContext();
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mTethering = makeTethering(mDeps);
- mTethering.startStateMachineUpdaters();
+ final TetheringDependencies deps = makeTetheringDependencies();
+ // The Tethering object needs a fully functional context to start, so this can't be done
+ // in the constructor.
+ mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
}
/**
@@ -92,21 +84,10 @@
return new Tethering(deps);
}
- /**
- * Create a binder connector for the system server to communicate with the tethering.
- */
- private synchronized IBinder makeConnector() {
- if (mConnector == null) {
- mConnector = new TetheringConnector(mTethering, TetheringService.this);
- }
- return mConnector;
- }
-
@NonNull
@Override
public IBinder onBind(Intent intent) {
- mLog.mark("onBind");
- return makeConnector();
+ return mConnector;
}
private static class TetheringConnector extends ITetheringConnector.Stub {
@@ -148,7 +129,11 @@
@Override
public void startTethering(TetheringRequestParcel request, String callerPkg,
IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, listener)) return;
+ if (checkAndNotifyCommonError(callerPkg,
+ request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
+ listener)) {
+ return;
+ }
mTethering.startTethering(request, listener);
}
@@ -175,7 +160,7 @@
public void registerTetheringEventCallback(ITetheringEventCallback callback,
String callerPkg) {
try {
- if (!mService.hasTetherAccessPermission()) {
+ if (!hasTetherAccessPermission()) {
callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
return;
}
@@ -187,7 +172,7 @@
public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
String callerPkg) {
try {
- if (!mService.hasTetherAccessPermission()) {
+ if (!hasTetherAccessPermission()) {
callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
return;
}
@@ -221,12 +206,17 @@
}
private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) {
+ return checkAndNotifyCommonError(callerPkg, false /* onlyAllowPrivileged */, listener);
+ }
+
+ private boolean checkAndNotifyCommonError(final String callerPkg,
+ final boolean onlyAllowPrivileged, final IIntResultListener listener) {
try {
- if (!mService.hasTetherChangePermission(callerPkg)) {
+ if (!hasTetherChangePermission(callerPkg, onlyAllowPrivileged)) {
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
return true;
}
- if (!mService.isTetheringSupported()) {
+ if (!mTethering.isTetheringSupported()) {
listener.onResult(TETHER_ERROR_UNSUPPORTED);
return true;
}
@@ -238,11 +228,11 @@
}
private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) {
- if (!mService.hasTetherChangePermission(callerPkg)) {
+ if (!hasTetherChangePermission(callerPkg, false /* onlyAllowPrivileged */)) {
receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
return true;
}
- if (!mService.isTetheringSupported()) {
+ if (!mTethering.isTetheringSupported()) {
receiver.send(TETHER_ERROR_UNSUPPORTED, null);
return true;
}
@@ -250,142 +240,109 @@
return false;
}
- }
-
- // if ro.tether.denied = true we default to no tethering
- // gservices could set the secure setting to 1 though to enable it on a build where it
- // had previously been turned off.
- private boolean isTetheringSupported() {
- final int defaultVal =
- SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
- final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
- final boolean tetherEnabledInSettings = tetherSupported
- && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
-
- return tetherEnabledInSettings && mTethering.hasTetherableConfiguration();
- }
-
- private boolean hasTetherChangePermission(String callerPkg) {
- if (checkCallingOrSelfPermission(
- android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) {
- return true;
+ private boolean hasTetherPrivilegedPermission() {
+ return mService.checkCallingOrSelfPermission(TETHER_PRIVILEGED) == PERMISSION_GRANTED;
}
- if (mTethering.isTetherProvisioningRequired()) return false;
+ private boolean hasTetherChangePermission(final String callerPkg,
+ final boolean onlyAllowPrivileged) {
+ if (hasTetherPrivilegedPermission()) return true;
+ if (onlyAllowPrivileged || mTethering.isTetherProvisioningRequired()) return false;
- int uid = Binder.getCallingUid();
- // If callerPkg's uid is not same as Binder.getCallingUid(),
- // checkAndNoteWriteSettingsOperation will return false and the operation will be denied.
- if (Settings.checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg,
- false /* throwException */)) {
- return true;
+ int uid = Binder.getCallingUid();
+ // If callerPkg's uid is not same as Binder.getCallingUid(),
+ // checkAndNoteWriteSettingsOperation will return false and the operation will be
+ // denied.
+ return Settings.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
+ false /* throwException */);
}
- return false;
+ private boolean hasTetherAccessPermission() {
+ if (hasTetherPrivilegedPermission()) return true;
+
+ return mService.checkCallingOrSelfPermission(
+ ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
+ }
}
- private boolean hasTetherAccessPermission() {
- if (checkCallingOrSelfPermission(
- android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) {
- return true;
- }
-
- if (checkCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_NETWORK_STATE) == PERMISSION_GRANTED) {
- return true;
- }
-
- return false;
- }
-
-
/**
* An injection method for testing.
*/
@VisibleForTesting
- public TetheringDependencies getTetheringDependencies() {
- if (mDeps == null) {
- mDeps = new TetheringDependencies() {
- @Override
- public NetworkRequest getDefaultNetworkRequest() {
- // TODO: b/147280869, add a proper system API to replace this.
- final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- return trackDefaultRequest;
- }
+ public TetheringDependencies makeTetheringDependencies() {
+ return new TetheringDependencies() {
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ // TODO: b/147280869, add a proper system API to replace this.
+ final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ return trackDefaultRequest;
+ }
- @Override
- public Looper getTetheringLooper() {
- final HandlerThread tetherThread = new HandlerThread("android.tethering");
- tetherThread.start();
- return tetherThread.getLooper();
- }
+ @Override
+ public Looper getTetheringLooper() {
+ final HandlerThread tetherThread = new HandlerThread("android.tethering");
+ tetherThread.start();
+ return tetherThread.getLooper();
+ }
- @Override
- public boolean isTetheringSupported() {
- return TetheringService.this.isTetheringSupported();
- }
+ @Override
+ public Context getContext() {
+ return TetheringService.this;
+ }
- @Override
- public Context getContext() {
- return TetheringService.this;
- }
+ @Override
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies() {
+ @Override
+ public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+ DhcpServerCallbacks cb) {
+ try {
+ final INetworkStackConnector service = getNetworkStackConnector();
+ if (service == null) return;
- @Override
- public IpServer.Dependencies getIpServerDependencies() {
- return new IpServer.Dependencies() {
- @Override
- public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
- DhcpServerCallbacks cb) {
+ service.makeDhcpServer(ifName, params, cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Fail to make dhcp server");
try {
- final INetworkStackConnector service = getNetworkStackConnector();
- if (service == null) return;
-
- service.makeDhcpServer(ifName, params, cb);
- } catch (RemoteException e) {
- Log.e(TAG, "Fail to make dhcp server");
- try {
- cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
- } catch (RemoteException re) { }
- }
+ cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
+ } catch (RemoteException re) { }
}
- };
- }
-
- // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
- // networkStackClient.
- static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
- private INetworkStackConnector getNetworkStackConnector() {
- IBinder connector;
- try {
- final long before = System.currentTimeMillis();
- while ((connector = NetworkStack.getService()) == null) {
- if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
- Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
- return null;
- }
- Thread.sleep(200);
- }
- } catch (InterruptedException e) {
- Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
- return null;
}
- return INetworkStackConnector.Stub.asInterface(connector);
- }
+ };
+ }
- @Override
- public BluetoothAdapter getBluetoothAdapter() {
- return BluetoothAdapter.getDefaultAdapter();
+ // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
+ // networkStackClient.
+ static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
+ private INetworkStackConnector getNetworkStackConnector() {
+ IBinder connector;
+ try {
+ final long before = System.currentTimeMillis();
+ while ((connector = NetworkStack.getService()) == null) {
+ if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
+ Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
+ return null;
+ }
+ Thread.sleep(200);
+ }
+ } catch (InterruptedException e) {
+ Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
+ return null;
}
- };
- }
- return mDeps;
+ return INetworkStackConnector.Stub.asInterface(connector);
+ }
+
+ @Override
+ public BluetoothAdapter getBluetoothAdapter() {
+ return BluetoothAdapter.getDefaultAdapter();
+ }
+ };
}
}
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 f9be7b9..b9622da 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -106,6 +106,7 @@
private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1";
private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
private static final int DHCP_LEASE_TIME_SECS = 3600;
+ private static final boolean DEFAULT_USING_BPF_OFFLOAD = true;
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
@@ -130,10 +131,11 @@
private NeighborEventConsumer mNeighborEventConsumer;
private void initStateMachine(int interfaceType) throws Exception {
- initStateMachine(interfaceType, false /* usingLegacyDhcp */);
+ initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD);
}
- private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
+ private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
+ boolean usingBpfOffload) throws Exception {
doAnswer(inv -> {
final IDhcpServerCallbacks cb = inv.getArgument(2);
new Thread(() -> {
@@ -165,7 +167,7 @@
mIpServer = new IpServer(
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd,
- mCallback, usingLegacyDhcp, mDependencies);
+ mCallback, usingLegacyDhcp, usingBpfOffload, mDependencies);
mIpServer.start();
mNeighborEventConsumer = neighborCaptor.getValue();
@@ -179,12 +181,13 @@
private void initTetheredStateMachine(int interfaceType, String upstreamIface)
throws Exception {
- initTetheredStateMachine(interfaceType, upstreamIface, false);
+ initTetheredStateMachine(interfaceType, upstreamIface, false,
+ DEFAULT_USING_BPF_OFFLOAD);
}
private void initTetheredStateMachine(int interfaceType, String upstreamIface,
- boolean usingLegacyDhcp) throws Exception {
- initStateMachine(interfaceType, usingLegacyDhcp);
+ boolean usingLegacyDhcp, boolean usingBpfOffload) throws Exception {
+ initStateMachine(interfaceType, usingLegacyDhcp, usingBpfOffload);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
if (upstreamIface != null) {
LinkProperties lp = new LinkProperties();
@@ -204,7 +207,8 @@
when(mDependencies.getIpNeighborMonitor(any(), any(), any()))
.thenReturn(mIpNeighborMonitor);
mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
- mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies);
+ mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD,
+ mDependencies);
mIpServer.start();
mLooper.dispatchAll();
verify(mCallback).updateInterfaceState(
@@ -494,7 +498,8 @@
@Test
public void doesNotStartDhcpServerIfDisabled() throws Exception {
- initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */,
+ DEFAULT_USING_BPF_OFFLOAD);
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
verify(mDependencies, never()).makeDhcpServer(any(), any(), any());
@@ -577,7 +582,8 @@
@Test
public void addRemoveipv6ForwardingRules() throws Exception {
- initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */);
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ DEFAULT_USING_BPF_OFFLOAD);
final int myIfindex = TEST_IFACE_PARAMS.index;
final int notMyIfindex = myIfindex - 1;
@@ -678,6 +684,53 @@
reset(mNetd);
}
+ @Test
+ public void enableDisableUsingBpfOffload() throws Exception {
+ final int myIfindex = TEST_IFACE_PARAMS.index;
+ final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1");
+ final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
+ final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00");
+
+ reset(mNetd);
+
+ // Expect that rules can be only added/removed when the BPF offload config is enabled.
+ // Note that the usingBpfOffload false case is not a realistic test case. Because IP
+ // neighbor monitor doesn't start if BPF offload is disabled, there should have no
+ // neighbor event listening. This is used for testing the protection check just in case.
+ // TODO: Perhaps remove this test once we don't need this check anymore.
+ for (boolean usingBpfOffload : new boolean[]{true, false}) {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ usingBpfOffload);
+
+ // A neighbor is added.
+ recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
+ if (usingBpfOffload) {
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
+ } else {
+ verify(mNetd, never()).tetherOffloadRuleAdd(any());
+ }
+ reset(mNetd);
+
+ // A neighbor is deleted.
+ recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
+ if (usingBpfOffload) {
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
+ } else {
+ verify(mNetd, never()).tetherOffloadRuleRemove(any());
+ }
+ reset(mNetd);
+ }
+ }
+
+ @Test
+ public void doesNotStartIpNeighborMonitorIfBpfOffloadDisabled() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ false /* usingBpfOffload */);
+
+ // IP neighbor monitor doesn't start if BPF offload is disabled.
+ verify(mIpNeighborMonitor, never()).start();
+ }
+
private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any());
verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks(
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index 8bd0edc..72fa916 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -37,6 +37,8 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -45,7 +47,7 @@
import android.content.res.Resources;
import android.net.util.SharedLog;
import android.os.Bundle;
-import android.os.Message;
+import android.os.Handler;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
import android.os.SystemProperties;
@@ -56,26 +58,22 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
-import java.util.ArrayList;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class EntitlementManagerTest {
- private static final int EVENT_EM_UPDATE = 1;
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
@@ -90,8 +88,8 @@
private final PersistableBundle mCarrierConfig = new PersistableBundle();
private final TestLooper mLooper = new TestLooper();
private Context mMockContext;
+ private Runnable mPermissionChangeCallback;
- private TestStateMachine mSM;
private WrappedEntitlementManager mEnMgr;
private TetheringConfiguration mConfig;
private MockitoSession mMockingSession;
@@ -112,9 +110,9 @@
public int uiProvisionCount = 0;
public int silentProvisionCount = 0;
- public WrappedEntitlementManager(Context ctx, StateMachine target,
- SharedLog log, int what) {
- super(ctx, target, log, what);
+ public WrappedEntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
+ super(ctx, h, log, callback);
}
public void reset() {
@@ -149,9 +147,8 @@
doReturn(false).when(
() -> SystemProperties.getBoolean(
eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean()));
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn(null).when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), anyString()));
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
@@ -169,8 +166,9 @@
when(mLog.forSubComponent(anyString())).thenReturn(mLog);
mMockContext = new MockContext(mContext);
- mSM = new TestStateMachine();
- mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE);
+ mPermissionChangeCallback = spy(() -> { });
+ mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog,
+ mPermissionChangeCallback);
mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
mEnMgr.setTetheringConfigurationFetcher(() -> {
@@ -180,10 +178,6 @@
@After
public void tearDown() throws Exception {
- if (mSM != null) {
- mSM.quit();
- mSM = null;
- }
mMockingSession.finishMocking();
}
@@ -350,68 +344,105 @@
mEnMgr.reset();
}
+ private void assertPermissionChangeCallback(InOrder inOrder) {
+ inOrder.verify(mPermissionChangeCallback, times(1)).run();
+ }
+
+ private void assertNoPermissionChange(InOrder inOrder) {
+ inOrder.verifyNoMoreInteractions();
+ }
+
@Test
public void verifyPermissionResult() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
mEnMgr.notifyUpstream(true);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
mLooper.dispatchAll();
+ // Permitted: false -> false
+ assertNoPermissionChange(inOrder);
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: false -> true
+ assertPermissionChangeCallback(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
}
@Test
public void verifyPermissionIfAllNotApproved() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
mEnMgr.notifyUpstream(true);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
+ // Permitted: false -> false
+ assertNoPermissionChange(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
mLooper.dispatchAll();
+ // Permitted: false -> false
+ assertNoPermissionChange(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
}
@Test
public void verifyPermissionIfAnyApproved() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
mEnMgr.notifyUpstream(true);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
- mLooper.dispatchAll();
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
mLooper.dispatchAll();
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
-
}
@Test
public void verifyPermissionWhenProvisioningNotStarted() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ assertNoPermissionChange(inOrder);
setupForRequiredProvisioning();
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+ assertNoPermissionChange(inOrder);
}
@Test
public void testRunTetherProvisioning() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
// 1. start ui provisioning, upstream is mobile
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
@@ -421,16 +452,22 @@
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 2. start no-ui provisioning
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(1, mEnMgr.silentProvisionCount);
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 3. tear down mobile, then start ui provisioning
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
@@ -438,44 +475,58 @@
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ assertNoPermissionChange(inOrder);
mEnMgr.reset();
+
// 4. switch upstream back to mobile
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 5. tear down mobile, then switch SIM
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
mEnMgr.reevaluateSimCardProvisioning(mConfig);
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ assertNoPermissionChange(inOrder);
mEnMgr.reset();
+
// 6. switch upstream back to mobile again
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(3, mEnMgr.silentProvisionCount);
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 7. start ui provisioning, upstream is mobile, downstream is ethernet
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true);
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ // Permitted: false -> true
+ assertPermissionChangeCallback(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 8. downstream is invalid
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ assertNoPermissionChange(inOrder);
mEnMgr.reset();
}
@@ -492,31 +543,32 @@
verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
}
- public class TestStateMachine extends StateMachine {
- public final ArrayList<Message> messages = new ArrayList<>();
- private final State
- mLoggingState = new EntitlementManagerTest.TestStateMachine.LoggingState();
+ @Test
+ public void testsetExemptedDownstreamType() throws Exception {
+ setupForRequiredProvisioning();
+ // Cellular upstream is not permitted when no entitlement result.
+ assertFalse(mEnMgr.isCellularUpstreamPermitted());
- class LoggingState extends State {
- @Override public void enter() {
- messages.clear();
- }
+ // If there is exempted downstream and no other non-exempted downstreams, cellular is
+ // permitted.
+ mEnMgr.setExemptedDownstreamType(TETHERING_WIFI);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
- @Override public void exit() {
- messages.clear();
- }
+ // If second downstream run entitlement check fail, cellular upstream is not permitted.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
+ mEnMgr.notifyUpstream(true);
+ mLooper.dispatchAll();
+ mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
+ mLooper.dispatchAll();
+ assertFalse(mEnMgr.isCellularUpstreamPermitted());
- @Override public boolean processMessage(Message msg) {
- messages.add(msg);
- return false;
- }
- }
+ // When second downstream is down, exempted downstream can use cellular upstream.
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ verify(mEntitlementFailedListener).onUiEntitlementFailed(TETHERING_USB);
+ mEnMgr.stopProvisioningIfNeeded(TETHERING_USB);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
- public TestStateMachine() {
- super("EntitlementManagerTest.TestStateMachine", mLooper.getLooper());
- addState(mLoggingState);
- setInitialState(mLoggingState);
- super.start();
- }
+ mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
+ assertFalse(mEnMgr.isCellularUpstreamPermitted());
}
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
index 088a663..b291438 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
@@ -29,15 +29,15 @@
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE;
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID;
import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
+import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
import static com.android.testutils.MiscAssertsKt.assertContainsAll;
import static com.android.testutils.MiscAssertsKt.assertThrows;
-import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals;
+import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals;
import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
@@ -63,10 +63,10 @@
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.RouteInfo;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
+import android.net.netstats.provider.NetworkStatsProvider;
import android.net.util.SharedLog;
import android.os.Handler;
-import android.os.Looper;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.test.mock.MockContentResolver;
@@ -75,7 +75,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.TestableNetworkStatsProviderCbBinder;
import org.junit.After;
import org.junit.Before;
@@ -109,17 +109,20 @@
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
@Mock private NetworkStatsManager mStatsManager;
- @Mock private INetworkStatsProviderCallback mTetherStatsProviderCb;
+ @Mock private TetheringConfiguration mTetherConfig;
+ // Late init since methods must be called by the thread that created this object.
+ private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider;
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
ArgumentCaptor.forClass(ArrayList.class);
private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
private MockContentResolver mContentResolver;
+ private final TestLooper mTestLooper = new TestLooper();
private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() {
@Override
- int getPerformPollInterval() {
- return 0;
+ public TetheringConfiguration getTetherConfig() {
+ return mTetherConfig;
}
};
@@ -131,6 +134,7 @@
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
FakeSettingsProvider.clearSettingsProvider();
+ when(mTetherConfig.getOffloadPollInterval()).thenReturn(-1); // Disabled.
}
@After public void tearDown() throws Exception {
@@ -150,12 +154,16 @@
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
}
+ private void setOffloadPollInterval(int interval) {
+ when(mTetherConfig.getOffloadPollInterval()).thenReturn(interval);
+ }
+
private void waitForIdle() {
- HandlerUtilsKt.waitForIdle(new Handler(Looper.getMainLooper()), WAIT_FOR_IDLE_TIMEOUT);
+ mTestLooper.dispatchAll();
}
private OffloadController makeOffloadController() throws Exception {
- OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
+ OffloadController offload = new OffloadController(new Handler(mTestLooper.getLooper()),
mHardware, mContentResolver, mStatsManager, new SharedLog("test"), mDeps);
final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider>
tetherStatsProviderCaptor =
@@ -164,6 +172,7 @@
tetherStatsProviderCaptor.capture());
mTetherStatsProvider = tetherStatsProviderCaptor.getValue();
assertNotNull(mTetherStatsProvider);
+ mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder();
mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb);
return offload;
}
@@ -352,9 +361,9 @@
stacked.setInterfaceName("stacked");
stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
stacked.addRoute(new RouteInfo(null, InetAddress.getByName("192.0.2.254"), null,
- RTN_UNICAST));
+ RTN_UNICAST));
stacked.addRoute(new RouteInfo(null, InetAddress.getByName("fe80::bad:f00"), null,
- RTN_UNICAST));
+ RTN_UNICAST));
assertTrue(lp.addStackedLink(stacked));
offload.setUpstreamLinkProperties(lp);
// No change in local addresses means no call to setLocalPrefixes().
@@ -459,20 +468,12 @@
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999))
.addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321));
- assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats));
- assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats));
-
- final ArgumentCaptor<NetworkStats> ifaceStatsCaptor = ArgumentCaptor.forClass(
- NetworkStats.class);
- final ArgumentCaptor<NetworkStats> uidStatsCaptor = ArgumentCaptor.forClass(
- NetworkStats.class);
+ assertNetworkStatsEquals(expectedIfaceStats, ifaceStats);
+ assertNetworkStatsEquals(expectedUidStats, uidStats);
// Force pushing stats update to verify the stats reported.
mTetherStatsProvider.pushTetherStats();
- verify(mTetherStatsProviderCb, times(1))
- .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture());
- assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue()));
- assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue()));
+ mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats);
when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
new ForwardedStats(100000, 100000));
@@ -498,11 +499,10 @@
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999))
.addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321));
- assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu));
- assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu));
+ assertNetworkStatsEquals(expectedIfaceStatsAccu, ifaceStatsAccu);
+ assertNetworkStatsEquals(expectedUidStatsAccu, uidStatsAccu);
// Verify that only diff of stats is reported.
- reset(mTetherStatsProviderCb);
mTetherStatsProvider.pushTetherStats();
final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2)
.addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0))
@@ -511,10 +511,8 @@
final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2)
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0))
.addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000));
- verify(mTetherStatsProviderCb, times(1))
- .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture());
- assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue()));
- assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue()));
+ mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff,
+ expectedUidStatsDiff);
}
@Test
@@ -591,7 +589,7 @@
OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
callback.onStoppedLimitReached();
- verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any());
+ mTetherStatsProviderCb.expectNotifyStatsUpdated();
}
@Test
@@ -695,8 +693,8 @@
verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
// TODO: verify the exact stats reported.
- verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any());
- verifyNoMoreInteractions(mTetherStatsProviderCb);
+ mTetherStatsProviderCb.expectNotifyStatsUpdated();
+ mTetherStatsProviderCb.assertNoCallback();
verifyNoMoreInteractions(mHardware);
}
@@ -760,8 +758,8 @@
// Verify forwarded stats behaviour.
verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
- verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any());
- verifyNoMoreInteractions(mTetherStatsProviderCb);
+ mTetherStatsProviderCb.expectNotifyStatsUpdated();
+ mTetherStatsProviderCb.assertNoCallback();
// TODO: verify local prefixes and downstreams are also pushed to the HAL.
verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
@@ -780,4 +778,50 @@
verifyNoMoreInteractions(mHardware);
}
+ @Test
+ public void testOnSetAlert() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+ setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ // Initialize with fake eth upstream.
+ final String ethernetIface = "eth1";
+ InOrder inOrder = inOrder(mHardware);
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+ // Previous upstream was null, so no stats are fetched.
+ inOrder.verify(mHardware, never()).getForwardedStats(any());
+
+ // Verify that set quota to 0 will immediately triggers an callback.
+ mTetherStatsProvider.onSetAlert(0);
+ waitForIdle();
+ mTetherStatsProviderCb.expectNotifyAlertReached();
+
+ // Verify that notifyAlertReached never fired if quota is not yet reached.
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
+ new ForwardedStats(0, 0));
+ mTetherStatsProvider.onSetAlert(100);
+ mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.assertNoCallback();
+
+ // Verify that notifyAlertReached fired when quota is reached.
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
+ new ForwardedStats(50, 50));
+ mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.expectNotifyAlertReached();
+
+ // Verify that set quota with UNLIMITED won't trigger any callback, and won't fetch
+ // any stats since the polling is stopped.
+ reset(mHardware);
+ mTetherStatsProvider.onSetAlert(NetworkStatsProvider.QUOTA_UNLIMITED);
+ mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.assertNoCallback();
+ verify(mHardware, never()).getForwardedStats(any());
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
new file mode 100644
index 0000000..f8ff1cb
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.networkstack.tethering;
+
+import static android.net.util.TetheringUtils.uint16;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
+import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
+import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
+import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
+import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
+import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.NativeHandle;
+import android.os.test.TestLooper;
+import android.system.OsConstants;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+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 java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class OffloadHardwareInterfaceTest {
+ private static final String RMNET0 = "test_rmnet_data0";
+
+ private final TestLooper mTestLooper = new TestLooper();
+
+ private OffloadHardwareInterface mOffloadHw;
+ private ITetheringOffloadCallback mTetheringOffloadCallback;
+ private OffloadHardwareInterface.ControlCallback mControlCallback;
+
+ @Mock private IOffloadConfig mIOffloadConfig;
+ @Mock private IOffloadControl mIOffloadControl;
+ @Mock private NativeHandle mNativeHandle;
+
+ class MyDependencies extends OffloadHardwareInterface.Dependencies {
+ MyDependencies(SharedLog log) {
+ super(log);
+ }
+
+ @Override
+ public IOffloadConfig getOffloadConfig() {
+ return mIOffloadConfig;
+ }
+
+ @Override
+ public IOffloadControl getOffloadControl() {
+ return mIOffloadControl;
+ }
+
+ @Override
+ public NativeHandle createConntrackSocket(final int groups) {
+ return mNativeHandle;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final SharedLog log = new SharedLog("test");
+ mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log,
+ new MyDependencies(log));
+ mControlCallback = spy(new OffloadHardwareInterface.ControlCallback());
+ }
+
+ private void startOffloadHardwareInterface() throws Exception {
+ mOffloadHw.initOffloadConfig();
+ mOffloadHw.initOffloadControl(mControlCallback);
+ final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor =
+ ArgumentCaptor.forClass(ITetheringOffloadCallback.class);
+ verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any());
+ mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue();
+ }
+
+ @Test
+ public void testGetForwardedStats() throws Exception {
+ startOffloadHardwareInterface();
+ final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0);
+ verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any());
+ assertNotNull(stats);
+ }
+
+ @Test
+ public void testSetLocalPrefixes() throws Exception {
+ startOffloadHardwareInterface();
+ final ArrayList<String> localPrefixes = new ArrayList<>();
+ localPrefixes.add("127.0.0.0/8");
+ localPrefixes.add("fe80::/64");
+ mOffloadHw.setLocalPrefixes(localPrefixes);
+ verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any());
+ }
+
+ @Test
+ public void testSetDataLimit() throws Exception {
+ startOffloadHardwareInterface();
+ final long limit = 12345;
+ mOffloadHw.setDataLimit(RMNET0, limit);
+ verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any());
+ }
+
+ @Test
+ public void testSetUpstreamParameters() throws Exception {
+ startOffloadHardwareInterface();
+ final String v4addr = "192.168.10.1";
+ final String v4gateway = "192.168.10.255";
+ final ArrayList<String> v6gws = new ArrayList<>(0);
+ v6gws.add("2001:db8::1");
+ mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws);
+ verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
+ eq(v6gws), any());
+
+ final ArgumentCaptor<ArrayList<String>> mArrayListCaptor =
+ ArgumentCaptor.forClass(ArrayList.class);
+ mOffloadHw.setUpstreamParameters(null, null, null, null);
+ verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""),
+ mArrayListCaptor.capture(), any());
+ assertEquals(mArrayListCaptor.getValue().size(), 0);
+ }
+
+ @Test
+ public void testUpdateDownstreamPrefix() throws Exception {
+ startOffloadHardwareInterface();
+ final String ifName = "wlan1";
+ final String prefix = "192.168.43.0/24";
+ mOffloadHw.addDownstreamPrefix(ifName, prefix);
+ verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any());
+
+ mOffloadHw.removeDownstreamPrefix(ifName, prefix);
+ verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any());
+ }
+
+ @Test
+ public void testTetheringOffloadCallback() throws Exception {
+ startOffloadHardwareInterface();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStarted();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStoppedError();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStoppedUnsupported();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onSupportAvailable();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStoppedLimitReached();
+
+ final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP);
+ mTetheringOffloadCallback.updateTimeout(tcpParams);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP),
+ eq(tcpParams.src.addr),
+ eq(uint16(tcpParams.src.port)),
+ eq(tcpParams.dst.addr),
+ eq(uint16(tcpParams.dst.port)));
+
+ final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP);
+ mTetheringOffloadCallback.updateTimeout(udpParams);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP),
+ eq(udpParams.src.addr),
+ eq(uint16(udpParams.src.port)),
+ eq(udpParams.dst.addr),
+ eq(uint16(udpParams.dst.port)));
+ }
+
+ private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
+ final NatTimeoutUpdate params = new NatTimeoutUpdate();
+ params.proto = proto;
+ params.src.addr = "192.168.43.200";
+ params.src.port = 100;
+ params.dst.addr = "172.50.46.169";
+ params.dst.port = 150;
+ return params;
+ }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index 07ddea4..1999ad7 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -30,7 +30,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -109,12 +108,14 @@
.mockStatic(DeviceConfig.class)
.strictness(Strictness.WARN)
.startMocking();
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn(null).when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn(
new String[0]);
+ when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn(
+ TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
.thenReturn(new String[]{ "test_wlan\\d" });
@@ -125,6 +126,8 @@
.thenReturn(new String[0]);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
+ initializeBpfOffloadConfiguration(true, null /* unset */);
+
mHasTelephonyManager = true;
mMockContext = new MockContext(mContext);
mEnableLegacyDhcpServer = false;
@@ -276,13 +279,57 @@
assertFalse(upstreamIterator.hasNext());
}
+ private void initializeBpfOffloadConfiguration(
+ final boolean fromRes, final String fromDevConfig) {
+ when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes);
+ doReturn(fromDevConfig).when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD)));
+ }
+
+ @Test
+ public void testBpfOffloadEnabledByResource() {
+ initializeBpfOffloadConfiguration(true, null /* unset */);
+ final TetheringConfiguration enableByRes =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(enableByRes.enableBpfOffload);
+ }
+
+ @Test
+ public void testBpfOffloadEnabledByDeviceConfigOverride() {
+ for (boolean res : new boolean[]{true, false}) {
+ initializeBpfOffloadConfiguration(res, "true");
+ final TetheringConfiguration enableByDevConOverride =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(enableByDevConOverride.enableBpfOffload);
+ }
+ }
+
+ @Test
+ public void testBpfOffloadDisabledByResource() {
+ initializeBpfOffloadConfiguration(false, null /* unset */);
+ final TetheringConfiguration disableByRes =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertFalse(disableByRes.enableBpfOffload);
+ }
+
+ @Test
+ public void testBpfOffloadDisabledByDeviceConfigOverride() {
+ for (boolean res : new boolean[]{true, false}) {
+ initializeBpfOffloadConfiguration(res, "false");
+ final TetheringConfiguration disableByDevConOverride =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertFalse(disableByDevConOverride.enableBpfOffload);
+ }
+ }
+
@Test
public void testNewDhcpServerDisabled() {
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
true);
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn("false").when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
final TetheringConfiguration enableByRes =
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -290,9 +337,9 @@
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
- doReturn(true).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn("true").when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
final TetheringConfiguration enableByDevConfig =
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -303,9 +350,9 @@
public void testNewDhcpServerEnabled() {
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn("false").when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
final TetheringConfiguration cfg =
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -314,6 +361,23 @@
}
@Test
+ public void testOffloadIntervalByResource() {
+ final TetheringConfiguration intervalByDefault =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertEquals(TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS,
+ intervalByDefault.getOffloadPollInterval());
+
+ final int[] testOverrides = {0, 3000, -1};
+ for (final int override : testOverrides) {
+ when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn(
+ override);
+ final TetheringConfiguration overrideByRes =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertEquals(override, overrideByRes.getOffloadPollInterval());
+ }
+ }
+
+ @Test
public void testGetResourcesBySubId() {
setUpResourceForSubId();
final TetheringConfiguration cfg = new TetheringConfiguration(
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 51bad9a..4a667b1 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -82,8 +82,7 @@
mTetheringConnector = mockConnector.getTetheringConnector();
final MockTetheringService service = mockConnector.getService();
mTethering = service.getTethering();
- verify(mTethering).startStateMachineUpdaters();
- when(mTethering.hasTetherableConfiguration()).thenReturn(true);
+ when(mTethering.isTetheringSupported()).thenReturn(true);
}
@After
@@ -96,7 +95,7 @@
when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).tether(TEST_IFACE_NAME);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -107,7 +106,7 @@
when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).untether(TEST_IFACE_NAME);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -118,7 +117,7 @@
when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).setUsbTethering(true /* enable */);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -130,7 +129,7 @@
final TetheringRequestParcel request = new TetheringRequestParcel();
request.tetheringType = TETHERING_WIFI;
mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).startTethering(eq(request), eq(result));
verifyNoMoreInteractions(mTethering);
}
@@ -139,7 +138,7 @@
public void testStopTethering() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).stopTethering(TETHERING_WIFI);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -150,7 +149,7 @@
final ResultReceiver result = new ResultReceiver(null);
mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
true /* showEntitlementUi */, TEST_CALLER_PKG);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
eq(result), eq(true) /* showEntitlementUi */);
verifyNoMoreInteractions(mTethering);
@@ -177,7 +176,7 @@
public void testStopAllTethering() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).untetherAll();
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -187,7 +186,7 @@
public void testIsTetheringSupported() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
}
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 0363f5f..0132aba 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
@@ -57,6 +57,7 @@
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
@@ -150,6 +151,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.ArrayList;
@@ -170,6 +173,8 @@
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
private static final String TEST_NCM_IFNAME = "test_ncm0";
private static final String TETHERING_NAME = "Tethering";
+ private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+ private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
@@ -212,6 +217,9 @@
private Tethering mTethering;
private PhoneStateListener mPhoneStateListener;
private InterfaceConfigurationParcel mInterfaceConfiguration;
+ private TetheringConfiguration mConfig;
+ private EntitlementManager mEntitleMgr;
+ private OffloadController mOffloadCtrl;
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
@@ -297,14 +305,15 @@
}
}
- private class MockTetheringConfiguration extends TetheringConfiguration {
- MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+ // MyTetheringConfiguration is used to override static method for testing.
+ private class MyTetheringConfiguration extends TetheringConfiguration {
+ MyTetheringConfiguration(Context ctx, SharedLog log, int id) {
super(ctx, log, id);
}
@Override
- protected boolean getDeviceConfigBoolean(final String name) {
- return false;
+ protected String getDeviceConfigProperty(final String name) {
+ return null;
}
@Override
@@ -328,6 +337,15 @@
}
@Override
+ public OffloadController getOffloadController(Handler h, SharedLog log,
+ OffloadController.Dependencies deps) {
+ mOffloadCtrl = spy(super.getOffloadController(h, log, deps));
+ // Return real object here instead of mock because
+ // testReportFailCallbackIfOffloadNotSupported depend on real OffloadController object.
+ return mOffloadCtrl;
+ }
+
+ @Override
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
StateMachine target, SharedLog log, int what) {
mUpstreamNetworkMonitorMasterSM = target;
@@ -352,6 +370,13 @@
}
@Override
+ public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
+ mEntitleMgr = spy(super.getEntitlementManager(ctx, h, log, callback));
+ return mEntitleMgr;
+ }
+
+ @Override
public boolean isTetheringSupported() {
return true;
}
@@ -359,7 +384,8 @@
@Override
public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
int subId) {
- return new MockTetheringConfiguration(ctx, log, subId);
+ mConfig = spy(new MyTetheringConfiguration(ctx, log, subId));
+ return mConfig;
}
@Override
@@ -459,18 +485,6 @@
MockitoAnnotations.initMocks(this);
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
- when(mResources.getStringArray(R.array.config_tether_usb_regexs))
- .thenReturn(new String[] { "test_rndis\\d" });
- when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
- .thenReturn(new String[]{ "test_wlan\\d" });
- when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
- .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
- when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
- when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
- .thenReturn(new String[] { "test_ncm\\d" });
- when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
- when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
when(mNetd.interfaceGetList())
@@ -489,6 +503,7 @@
mServiceContext = new TestContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ setTetheringSupported(true /* supported */);
mIntents = new Vector<>();
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -499,7 +514,6 @@
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mTethering = makeTethering();
- mTethering.startStateMachineUpdaters();
verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any());
verify(mNetd).registerUnsolicitedEventListener(any());
final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
@@ -510,22 +524,47 @@
mPhoneStateListener = phoneListenerCaptor.getValue();
}
+ private void setTetheringSupported(final boolean supported) {
+ Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED,
+ supported ? 1 : 0);
+ when(mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported);
+ // Setup tetherable configuration.
+ when(mResources.getStringArray(R.array.config_tether_usb_regexs))
+ .thenReturn(new String[] { "test_rndis\\d" });
+ when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
+ .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
+ when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
+ .thenReturn(new String[] { "test_ncm\\d" });
+ when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
+ when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true);
+ }
+
+ private void initTetheringUpstream(UpstreamNetworkState upstreamState) {
+ when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
+ when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ }
+
private Tethering makeTethering() {
mTetheringDependencies.reset();
return new Tethering(mTetheringDependencies);
}
private TetheringRequestParcel createTetheringRequestParcel(final int type) {
- return createTetheringRequestParcel(type, null, null);
+ return createTetheringRequestParcel(type, null, null, false);
}
private TetheringRequestParcel createTetheringRequestParcel(final int type,
- final LinkAddress serverAddr, final LinkAddress clientAddr) {
+ final LinkAddress serverAddr, final LinkAddress clientAddr, final boolean exempt) {
final TetheringRequestParcel request = new TetheringRequestParcel();
request.tetheringType = type;
request.localIPv4Address = serverAddr;
request.staticClientAddress = clientAddr;
- request.exemptFromEntitlementCheck = false;
+ request.exemptFromEntitlementCheck = exempt;
request.showProvisioningUi = false;
return request;
@@ -646,9 +685,7 @@
}
private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
- when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
// Emulate pressing the USB tethering button in Settings UI.
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
@@ -674,7 +711,7 @@
verify(mNetd, times(1)).interfaceGetList();
// UpstreamNetworkMonitor should receive selected upstream
- verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
+ verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
}
@@ -846,8 +883,7 @@
// Then 464xlat comes up
upstreamState = buildMobile464xlatUpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
// Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
@@ -1318,9 +1354,7 @@
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
// 2. Enable wifi tethering.
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
- when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
mLooper.dispatchAll();
@@ -1636,7 +1670,7 @@
// Enable USB tethering and check that Tethering starts USB.
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
- null, null), firstResult);
+ null, null, false), firstResult);
mLooper.dispatchAll();
firstResult.assertHasResult();
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
@@ -1644,7 +1678,7 @@
// Enable USB tethering again with the same request and expect no change to USB.
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
- null, null), secondResult);
+ null, null, false), secondResult);
mLooper.dispatchAll();
secondResult.assertHasResult();
verify(mUsbManager, never()).setCurrentFunctions(UsbManager.FUNCTION_NONE);
@@ -1653,7 +1687,7 @@
// Enable USB tethering with a different request and expect that USB is stopped and
// started.
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
- serverLinkAddr, clientLinkAddr), thirdResult);
+ serverLinkAddr, clientLinkAddr, false), thirdResult);
mLooper.dispatchAll();
thirdResult.assertHasResult();
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
@@ -1677,7 +1711,7 @@
final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor =
ArgumentCaptor.forClass(DhcpServingParamsParcel.class);
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
- serverLinkAddr, clientLinkAddr), null);
+ serverLinkAddr, clientLinkAddr, false), null);
mLooper.dispatchAll();
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
@@ -1697,7 +1731,7 @@
final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network));
@@ -1709,7 +1743,7 @@
final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);
@@ -1726,6 +1760,82 @@
verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any());
}
+ @Test
+ public void testDumpTetheringLog() throws Exception {
+ final FileDescriptor mockFd = mock(FileDescriptor.class);
+ final PrintWriter mockPw = mock(PrintWriter.class);
+ runUsbTethering(null);
+ mLooper.startAutoDispatch();
+ mTethering.dump(mockFd, mockPw, new String[0]);
+ verify(mConfig).dump(any());
+ verify(mEntitleMgr).dump(any());
+ verify(mOffloadCtrl).dump(any());
+ mLooper.stopAutoDispatch();
+ }
+
+ @Test
+ public void testExemptFromEntitlementCheck() throws Exception {
+ setupForRequiredProvisioning();
+ final TetheringRequestParcel wifiNotExemptRequest =
+ createTetheringRequestParcel(TETHERING_WIFI, null, null, false);
+ mTethering.startTethering(wifiNotExemptRequest, null);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr).startProvisioningIfNeeded(TETHERING_WIFI, false);
+ verify(mEntitleMgr, never()).setExemptedDownstreamType(TETHERING_WIFI);
+ assertFalse(mEntitleMgr.isCellularUpstreamPermitted());
+ mTethering.stopTethering(TETHERING_WIFI);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr).stopProvisioningIfNeeded(TETHERING_WIFI);
+ reset(mEntitleMgr);
+
+ setupForRequiredProvisioning();
+ final TetheringRequestParcel wifiExemptRequest =
+ createTetheringRequestParcel(TETHERING_WIFI, null, null, true);
+ mTethering.startTethering(wifiExemptRequest, null);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr, never()).startProvisioningIfNeeded(TETHERING_WIFI, false);
+ verify(mEntitleMgr).setExemptedDownstreamType(TETHERING_WIFI);
+ assertTrue(mEntitleMgr.isCellularUpstreamPermitted());
+ mTethering.stopTethering(TETHERING_WIFI);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr).stopProvisioningIfNeeded(TETHERING_WIFI);
+ reset(mEntitleMgr);
+
+ // If one app enables tethering without provisioning check first, then another app enables
+ // tethering of the same type but does not disable the provisioning check.
+ setupForRequiredProvisioning();
+ mTethering.startTethering(wifiExemptRequest, null);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr, never()).startProvisioningIfNeeded(TETHERING_WIFI, false);
+ verify(mEntitleMgr).setExemptedDownstreamType(TETHERING_WIFI);
+ assertTrue(mEntitleMgr.isCellularUpstreamPermitted());
+ reset(mEntitleMgr);
+ setupForRequiredProvisioning();
+ mTethering.startTethering(wifiNotExemptRequest, null);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr).startProvisioningIfNeeded(TETHERING_WIFI, false);
+ verify(mEntitleMgr, never()).setExemptedDownstreamType(TETHERING_WIFI);
+ assertFalse(mEntitleMgr.isCellularUpstreamPermitted());
+ mTethering.stopTethering(TETHERING_WIFI);
+ mLooper.dispatchAll();
+ verify(mEntitleMgr).stopProvisioningIfNeeded(TETHERING_WIFI);
+ reset(mEntitleMgr);
+ }
+
+ private void setupForRequiredProvisioning() {
+ // Produce some acceptable looking provision app setting if requested.
+ when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(PROVISIONING_APP_NAME);
+ when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
+ .thenReturn(PROVISIONING_NO_UI_APP_NAME);
+ // Act like the CarrierConfigManager is present and ready unless told otherwise.
+ when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
+ .thenReturn(mCarrierConfigManager);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig);
+ mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
+ mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+ sendConfigurationChanged();
+ }
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
index 210fdc6..3e053d5 100644
--- a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -20,9 +20,9 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.util.LongSparseArray;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Pools.Pool;
import android.util.Pools.SynchronizedPool;
import android.view.View;
@@ -163,7 +163,7 @@
private static boolean isHighResolution(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
- context.getDisplayNoVerify().getMetrics(metrics);
+ context.getDisplayNoVerify().getRealMetrics(metrics);
return metrics.heightPixels > 2048 || metrics.widthPixels > 2048;
}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index fe9f60f..d8184f2 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -40,6 +40,7 @@
import android.view.Display;
import android.view.View;
import android.widget.Toast;
+import android.window.WindowMetricsHelper;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.exif.ExifInterface;
@@ -357,7 +358,8 @@
// Get the crop
boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
- Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds();
+ Rect windowBounds = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ getWindowManager().getCurrentWindowMetrics());
boolean isPortrait = windowBounds.width() < windowBounds.height();
Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-nl/strings.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-nl/strings.xml
index 4e947cb..bf49cec 100644
--- a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-nl/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-nl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="7305489596221077240">"Punch Hole-cutout"</string>
+ <string name="display_cutout_emulation_overlay" msgid="7305489596221077240">"Cameragat-cutout"</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-nl/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-nl/strings.xml
index a778407..6abedbd 100644
--- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-nl/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-nl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Waterfall-cutout"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Waterval-cutout"</string>
</resources>
diff --git a/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml b/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml
index 8e80c9d..63ba20e 100644
--- a/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml
@@ -24,6 +24,5 @@
<!-- Corner radius for bottom sheet system dialogs -->
<dimen name="config_bottomDialogCornerRadius">0dp</dimen>
<!-- Tile stroke width -->
- <dimen name="config_qsTileStrokeWidthInactive">10dp</dimen>
-
+ <dimen name="config_qsTileStrokeWidthInactive">1dp</dimen>
</resources>
diff --git a/services/Android.bp b/services/Android.bp
index 2e70f1c..882085a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -80,6 +80,8 @@
"services.usb",
"services.voiceinteraction",
"services.wifi",
+ "service-blobstore",
+ "service-jobscheduler",
"android.hidl.base-V1.0-java",
],
@@ -135,7 +137,7 @@
},
last_released: {
api_file: ":android.api.system-server.latest",
- removed_api_file: "api/removed.txt",
+ removed_api_file: ":removed.api.system-server.latest",
baseline_file: ":system-server-api-incompatibilities-with-last-released"
},
api_lint: {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 02ab60b..b3867a3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -20,8 +20,10 @@
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static android.view.accessibility.AccessibilityManager.ShortcutType;
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
+import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;
@@ -130,6 +132,7 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Predicate;
/**
* This class is instantiated by the system as a system level service and can be
@@ -389,7 +392,7 @@
return;
}
// We will update when the automation service dies.
- AccessibilityUserState userState = getCurrentUserStateLocked();
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
// We have to reload the installed services since some services may
// have different attributes, resolve info (does not support equals),
// etc. Remove them then to force reload.
@@ -438,15 +441,18 @@
if (userId != mCurrentUserId) {
return;
}
- AccessibilityUserState userState = getUserStateLocked(userId);
- Iterator<ComponentName> it = userState.mEnabledServices.iterator();
+ final AccessibilityUserState userState = getUserStateLocked(userId);
+ final Predicate<ComponentName> filter =
+ component -> component != null && component.getPackageName().equals(
+ packageName);
+ userState.mBindingServices.removeIf(filter);
+ userState.mCrashedServices.removeIf(filter);
+ final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
while (it.hasNext()) {
- ComponentName comp = it.next();
- String compPkg = comp.getPackageName();
+ final ComponentName comp = it.next();
+ final String compPkg = comp.getPackageName();
if (compPkg.equals(packageName)) {
it.remove();
- userState.getBindingServicesLocked().remove(comp);
- userState.getCrashedServicesLocked().remove(comp);
// Update the enabled services setting.
persistComponentNamesToSettingLocked(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
@@ -474,11 +480,11 @@
if (userId != mCurrentUserId) {
return false;
}
- AccessibilityUserState userState = getUserStateLocked(userId);
- Iterator<ComponentName> it = userState.mEnabledServices.iterator();
+ final AccessibilityUserState userState = getUserStateLocked(userId);
+ final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
while (it.hasNext()) {
- ComponentName comp = it.next();
- String compPkg = comp.getPackageName();
+ final ComponentName comp = it.next();
+ final String compPkg = comp.getPackageName();
for (String pkg : packages) {
if (compPkg.equals(pkg)) {
if (!doit) {
@@ -1206,7 +1212,7 @@
final Intent intent = new Intent();
final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
intent.setComponent(name);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
} catch (ActivityNotFoundException ignore) {
@@ -1538,6 +1544,7 @@
} else {
if (service != null) {
service.unbindLocked();
+ removeShortcutTargetForUnboundServiceLocked(userState, service);
}
}
}
@@ -2312,6 +2319,36 @@
scheduleNotifyClientsOfServicesStateChangeLocked(userState);
}
+ /**
+ * Remove the shortcut target for the unbound service which is requesting accessibility button
+ * and targeting sdk > Q from the accessibility button and shortcut.
+ *
+ * @param userState The accessibility user state.
+ * @param service The unbound service.
+ */
+ private void removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState,
+ AccessibilityServiceConnection service) {
+ if (!service.mRequestAccessibilityButton
+ || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo
+ .targetSdkVersion <= Build.VERSION_CODES.Q) {
+ return;
+ }
+ final ComponentName serviceName = service.getComponentName();
+ if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) {
+ final Set<String> currentTargets = userState.getShortcutTargetsLocked(
+ ACCESSIBILITY_SHORTCUT_KEY);
+ persistColonDelimitedSetToSettingLocked(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ userState.mUserId, currentTargets, str -> str);
+ }
+ if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) {
+ final Set<String> currentTargets = userState.getShortcutTargetsLocked(
+ ACCESSIBILITY_BUTTON);
+ persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+ userState.mUserId, currentTargets, str -> str);
+ }
+ }
+
private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) {
int newNonInteractiveUiTimeout = userState.getUserNonInteractiveUiTimeoutLocked();
int newInteractiveUiTimeout = userState.getUserInteractiveUiTimeoutLocked();
@@ -2422,6 +2459,8 @@
}
// In case user assigned magnification to the given shortcut.
if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) {
+ final boolean enabled = !getMagnificationController().isMagnifying(displayId);
+ logAccessibilityShortcutActivated(MAGNIFICATION_COMPONENT_NAME, shortcutType, enabled);
sendAccessibilityButtonToInputFilter(displayId);
return;
}
@@ -2431,11 +2470,12 @@
return;
}
// In case user assigned an accessibility framework feature to the given shortcut.
- if (performAccessibilityFrameworkFeature(targetComponentName)) {
+ if (performAccessibilityFrameworkFeature(targetComponentName, shortcutType)) {
return;
}
// In case user assigned an accessibility shortcut target to the given shortcut.
if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) {
+ logAccessibilityShortcutActivated(targetComponentName, shortcutType);
return;
}
// in case user assigned an accessibility service to the given shortcut.
@@ -2445,7 +2485,8 @@
}
}
- private boolean performAccessibilityFrameworkFeature(ComponentName assignedTarget) {
+ private boolean performAccessibilityFrameworkFeature(ComponentName assignedTarget,
+ @ShortcutType int shortcutType) {
final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
if (!frameworkFeatureMap.containsKey(assignedTarget)) {
@@ -2457,8 +2498,12 @@
featureInfo.getSettingKey(), mCurrentUserId);
// Assuming that the default state will be to have the feature off
if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) {
+ logAccessibilityShortcutActivated(assignedTarget, shortcutType, /* serviceEnabled= */
+ true);
setting.write(featureInfo.getSettingOnValue());
} else {
+ logAccessibilityShortcutActivated(assignedTarget, shortcutType, /* serviceEnabled= */
+ false);
setting.write(featureInfo.getSettingOffValue());
}
return true;
@@ -2520,8 +2565,13 @@
if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
|| (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) {
if (serviceConnection == null) {
+ logAccessibilityShortcutActivated(assignedTarget,
+ shortcutType, /* serviceEnabled= */ true);
enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
+
} else {
+ logAccessibilityShortcutActivated(assignedTarget,
+ shortcutType, /* serviceEnabled= */ false);
disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
}
return true;
@@ -2541,6 +2591,9 @@
+ assignedTarget);
return false;
}
+ // ServiceConnection means service enabled.
+ logAccessibilityShortcutActivated(assignedTarget, shortcutType, /* serviceEnabled= */
+ true);
serviceConnection.notifyAccessibilityButtonClickedLocked(displayId);
return true;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index edb4445..0f98992 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -94,8 +94,10 @@
if (userState == null) return;
final long identity = Binder.clearCallingIdentity();
try {
- int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+ int flags = Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
+ | Context.BIND_INCLUDE_CAPABILITIES;
if (userState.getBindInstantServiceAllowedLocked()) {
flags |= Context.BIND_ALLOW_INSTANT;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index bad649a..43bb4b3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -631,6 +631,25 @@
}
/**
+ * Removes given shortcut target in the list.
+ *
+ * @param shortcutType The shortcut type.
+ * @param target The component name of the shortcut target.
+ * @return true if the shortcut target is removed.
+ */
+ public boolean removeShortcutTargetLocked(@ShortcutType int shortcutType,
+ ComponentName target) {
+ return getShortcutTargetsLocked(shortcutType).removeIf(name -> {
+ ComponentName componentName;
+ if (name == null
+ || (componentName = ComponentName.unflattenFromString(name)) == null) {
+ return false;
+ }
+ return componentName.equals(target);
+ });
+ }
+
+ /**
* Returns installed accessibility service info by the given service component name.
*/
public AccessibilityServiceInfo getInstalledServiceInfoLocked(ComponentName componentName) {
diff --git a/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java
index 9e4fd80..afe6238 100644
--- a/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java
@@ -24,6 +24,7 @@
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logMagnificationTripleTap;
import static com.android.server.accessibility.gestures.GestureUtils.distance;
import static java.lang.Math.abs;
@@ -759,10 +760,17 @@
// Shortcut acts as the 2 initial taps
if (mShortcutTriggered) return tapCount() + 2 >= numTaps;
- return mDetectTripleTap
+ final boolean multitapTriggered = mDetectTripleTap
&& tapCount() >= numTaps
&& isMultiTap(mPreLastDown, mLastDown)
&& isMultiTap(mPreLastUp, mLastUp);
+
+ // Only log the triple tap event, use numTaps to filter.
+ if (multitapTriggered && numTaps > 2) {
+ final boolean enabled = mMagnificationController.isMagnifying(mDisplayId);
+ logMagnificationTripleTap(enabled);
+ }
+ return multitapTriggered;
}
private boolean isMultiTap(MotionEvent first, MotionEvent second) {
@@ -885,7 +893,6 @@
}
private void onTripleTap(MotionEvent up) {
-
if (DEBUG_DETECTING) {
Slog.i(LOG_TAG, "onTripleTap(); delayed: "
+ MotionEventInfo.toString(mDelayedEventQueue));
@@ -908,6 +915,10 @@
mViewportDraggingState.mZoomedInBeforeDrag =
mMagnificationController.isMagnifying(mDisplayId);
+ // Triple tap and hold also belongs to triple tap event.
+ final boolean enabled = !mViewportDraggingState.mZoomedInBeforeDrag;
+ logMagnificationTripleTap(enabled);
+
zoomOn(down.getX(), down.getY());
transitionTo(mViewportDraggingState);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index a14584a..4b89731 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -20,9 +20,9 @@
import static com.android.server.accessibility.gestures.GestureUtils.MM_PER_CM;
import static com.android.server.accessibility.gestures.GestureUtils.getActionIndex;
-import static com.android.server.accessibility.gestures.Swipe.CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS;
-import static com.android.server.accessibility.gestures.Swipe.CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS;
import static com.android.server.accessibility.gestures.Swipe.GESTURE_CONFIRM_CM;
+import static com.android.server.accessibility.gestures.Swipe.MAX_TIME_TO_CONTINUE_SWIPE_MS;
+import static com.android.server.accessibility.gestures.Swipe.MAX_TIME_TO_START_SWIPE_MS;
import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
import android.content.Context;
@@ -387,10 +387,10 @@
cancelPendingTransitions();
switch (getState()) {
case STATE_CLEAR:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS, event, rawEvent, policyFlags);
+ cancelAfter(MAX_TIME_TO_START_SWIPE_MS, event, rawEvent, policyFlags);
break;
case STATE_GESTURE_STARTED:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS, event, rawEvent, policyFlags);
+ cancelAfter(MAX_TIME_TO_CONTINUE_SWIPE_MS, event, rawEvent, policyFlags);
break;
default:
break;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
index 9108c69..041b424 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
@@ -49,11 +49,10 @@
// Buffer for storing points for gesture detection.
private final ArrayList<PointF> mStrokeBuffer = new ArrayList<>(100);
- // The minimal delta between moves to add a gesture point.
- private static final int TOUCH_TOLERANCE_PIX = 3;
-
- // The minimal score for accepting a predicted gesture.
- private static final float MIN_PREDICTION_SCORE = 2.0f;
+ // Constants for sampling motion event points.
+ // We sample based on a minimum distance between points, primarily to improve accuracy by
+ // reducing noisy minor changes in direction.
+ private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
// Distance a finger must travel before we decide if it is a gesture or not.
public static final int GESTURE_CONFIRM_CM = 1;
@@ -67,22 +66,19 @@
// all gestures started with the initial movement taking less than 100ms.
// When touch exploring, the first movement almost always takes longer than
// 200ms.
- public static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+ public static final long MAX_TIME_TO_START_SWIPE_MS = 150 * GESTURE_CONFIRM_CM;
// Time threshold used to determine if a gesture should be cancelled. If
- // the finger takes more than this time to move 1cm, the ongoing gesture is
- // cancelled.
- public static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
+ // the finger takes more than this time to move to the next sample point, the ongoing gesture
+ // is cancelled.
+ public static final long MAX_TIME_TO_CONTINUE_SWIPE_MS = 350 * GESTURE_CONFIRM_CM;
private int[] mDirections;
private float mBaseX;
private float mBaseY;
+ private long mBaseTime;
private float mPreviousGestureX;
private float mPreviousGestureY;
- // Constants for sampling motion event points.
- // We sample based on a minimum distance between points, primarily to improve accuracy by
- // reducing noisy minor changes in direction.
- private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
private final float mMinPixelsBetweenSamplesX;
private final float mMinPixelsBetweenSamplesY;
// The minmimum distance the finger must travel before we evaluate the initial direction of the
@@ -134,16 +130,19 @@
protected void clear() {
mBaseX = Float.NaN;
mBaseY = Float.NaN;
+ mBaseTime = 0;
+ mPreviousGestureX = Float.NaN;
+ mPreviousGestureY = Float.NaN;
mStrokeBuffer.clear();
super.clear();
}
@Override
protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
if (Float.isNaN(mBaseX) && Float.isNaN(mBaseY)) {
mBaseX = rawEvent.getX();
mBaseY = rawEvent.getY();
+ mBaseTime = rawEvent.getEventTime();
mPreviousGestureX = mBaseX;
mPreviousGestureY = mBaseY;
}
@@ -154,9 +153,11 @@
protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final float x = rawEvent.getX();
final float y = rawEvent.getY();
+ final long time = rawEvent.getEventTime();
final float dX = Math.abs(x - mPreviousGestureX);
final float dY = Math.abs(y - mPreviousGestureY);
final double moveDelta = Math.hypot(Math.abs(x - mBaseX), Math.abs(y - mBaseY));
+ final long timeDelta = time - mBaseTime;
if (DEBUG) {
Slog.d(
getGestureName(),
@@ -171,34 +172,38 @@
return;
} else if (mStrokeBuffer.size() == 0) {
// First, make sure the pointer is going in the right direction.
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
int direction = toDirection(x - mBaseX, y - mBaseY);
if (direction != mDirections[0]) {
cancelGesture(event, rawEvent, policyFlags);
return;
- } else {
- // This is confirmed to be some kind of swipe so start tracking points.
- mStrokeBuffer.add(new PointF(mBaseX, mBaseY));
}
- }
- if (moveDelta > mGestureDetectionThresholdPixels) {
- // If the pointer has moved more than the threshold,
- // update the stored values.
- mBaseX = x;
- mBaseY = y;
- if (getState() == STATE_CLEAR) {
- startGesture(event, rawEvent, policyFlags);
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
- }
+ // This is confirmed to be some kind of swipe so start tracking points.
+ mStrokeBuffer.add(new PointF(mBaseX, mBaseY));
}
}
- if (getState() == STATE_GESTURE_STARTED) {
- if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
- mPreviousGestureX = x;
- mPreviousGestureY = y;
- mStrokeBuffer.add(new PointF(x, y));
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ if (moveDelta > mGestureDetectionThresholdPixels) {
+ // This is a gesture, not touch exploration.
+ mBaseX = x;
+ mBaseY = y;
+ mBaseTime = time;
+ startGesture(event, rawEvent, policyFlags);
+ } else if (getState() == STATE_CLEAR) {
+ if (timeDelta > MAX_TIME_TO_START_SWIPE_MS) {
+ // The user isn't moving fast enough.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
}
+ } else if (getState() == STATE_GESTURE_STARTED) {
+ if (timeDelta > MAX_TIME_TO_CONTINUE_SWIPE_MS) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ }
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+ // At this point gesture detection has started and we are sampling points.
+ mPreviousGestureX = x;
+ mPreviousGestureY = y;
+ mStrokeBuffer.add(new PointF(x, y));
}
}
@@ -230,25 +235,6 @@
}
/**
- * queues a transition to STATE_GESTURE_CANCEL based on the current state. If we have
- * transitioned to STATE_GESTURE_STARTED the delay is longer.
- */
- private void cancelAfterPauseThreshold(
- MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cancelPendingTransitions();
- switch (getState()) {
- case STATE_CLEAR:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS, event, rawEvent, policyFlags);
- break;
- case STATE_GESTURE_STARTED:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS, event, rawEvent, policyFlags);
- break;
- default:
- break;
- }
- }
-
- /**
* Looks at the sequence of motions in mStrokeBuffer, classifies the gesture, then calls
* Listener callbacks for success or failure.
*
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 0b3899d..103151d 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -120,7 +120,7 @@
this::removeAppPredictionSessionInfo));
}
final boolean serviceExists = resolveService(sessionId, s ->
- s.onCreatePredictionSession(context, sessionId));
+ s.onCreatePredictionSession(context, sessionId), true);
if (!serviceExists) {
mSessionInfos.remove(sessionId);
}
@@ -132,7 +132,7 @@
@GuardedBy("mLock")
public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull AppTargetEvent event) {
- resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event));
+ resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false);
}
/**
@@ -142,7 +142,7 @@
public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
resolveService(sessionId, s ->
- s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
+ s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false);
}
/**
@@ -151,7 +151,7 @@
@GuardedBy("mLock")
public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback));
+ resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true);
}
/**
@@ -161,7 +161,7 @@
public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
final boolean serviceExists = resolveService(sessionId, s ->
- s.registerPredictionUpdates(sessionId, callback));
+ s.registerPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (serviceExists && sessionInfo != null) {
sessionInfo.addCallbackLocked(callback);
@@ -175,7 +175,7 @@
public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
final boolean serviceExists = resolveService(sessionId, s ->
- s.unregisterPredictionUpdates(sessionId, callback));
+ s.unregisterPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (serviceExists && sessionInfo != null) {
sessionInfo.removeCallbackLocked(callback);
@@ -187,7 +187,7 @@
*/
@GuardedBy("mLock")
public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
- resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId));
+ resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true);
}
/**
@@ -196,7 +196,7 @@
@GuardedBy("mLock")
public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
final boolean serviceExists = resolveService(sessionId, s ->
- s.onDestroyPredictionSession(sessionId));
+ s.onDestroyPredictionSession(sessionId), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (serviceExists && sessionInfo != null) {
sessionInfo.destroy();
@@ -267,6 +267,9 @@
mRemoteService.destroy();
mRemoteService = null;
+ synchronized (mLock) {
+ mZombie = true;
+ }
mRemoteService = getRemoteServiceLocked();
if (mRemoteService != null) {
if (isDebug()) {
@@ -304,7 +307,8 @@
@GuardedBy("mLock")
@Nullable
protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
- @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
+ @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb,
+ boolean sendImmediately) {
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (sessionInfo == null) return false;
if (sessionInfo.mUsesPeopleService) {
@@ -322,7 +326,13 @@
} else {
final RemoteAppPredictionService service = getRemoteServiceLocked();
if (service != null) {
- service.scheduleOnResolvedService(cb);
+ // TODO(b/155887722): implement a priority system so that latency-sensitive
+ // requests gets executed first.
+ if (sendImmediately) {
+ service.executeOnResolvedService(cb);
+ } else {
+ service.scheduleOnResolvedService(cb);
+ }
}
return service != null;
}
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
index ceb1caf..a57ff11 100644
--- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -80,6 +80,13 @@
}
/**
+ * Execute async request on remote service immediately instead of sending it to Handler queue.
+ */
+ public void executeOnResolvedService(@NonNull AsyncRequest<IPredictionService> request) {
+ executeAsyncRequest(request);
+ }
+
+ /**
* Failure callback
*/
public interface RemoteAppPredictionServiceCallbacks
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 74e4e4a..d7a3a32 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,7 +19,6 @@
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.UserIdInt;
@@ -101,7 +100,6 @@
import android.view.Display;
import android.view.View;
import android.widget.RemoteViews;
-
import com.android.internal.R;
import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.app.UnlaunchableAppActivity;
@@ -116,11 +114,6 @@
import com.android.server.LocalServices;
import com.android.server.WidgetBackupProvider;
import com.android.server.policy.IconUtilities;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -142,6 +135,9 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
OnCrossProfileWidgetProvidersChangeListener {
@@ -4887,7 +4883,7 @@
final int widgetCount = mWidgets.size();
for (int i = 0; i < widgetCount; i++) {
final Widget widget = mWidgets.get(i);
- if (widget.host.id.uid == uid) {
+ if (widget.host.id.uid == uid && widget.provider != null) {
if (widgetPackages == null) {
widgetPackages = new ArraySet<>();
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 3612e09..3dd2433 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -17,17 +17,17 @@
package com.android.server.autofill;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Bundle;
import android.os.Handler;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
-import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
-import java.util.Collections;
import java.util.Optional;
import java.util.function.Consumer;
@@ -46,8 +46,12 @@
@NonNull
private final Handler mHandler;
+ @Nullable
@GuardedBy("mLock")
private AutofillInlineSuggestionsRequestSession mSession;
+ @Nullable
+ @GuardedBy("mLock")
+ private InlineFillUi mInlineFillUi;
AutofillInlineSessionController(InputMethodManagerInternal inputMethodManagerInternal,
int userId, ComponentName componentName, Handler handler, Object lock) {
@@ -63,8 +67,8 @@
* Requests the IME to create an {@link InlineSuggestionsRequest} for {@code autofillId}.
*
* @param autofillId the Id of the field for which the request is for.
- * @param requestConsumer the callback which will be invoked when IME responded or if it times
- * out waiting for IME response.
+ * @param requestConsumer the callback to be invoked when the IME responds. Note that this is
+ * never invoked if the IME doesn't respond.
*/
@GuardedBy("mLock")
void onCreateInlineSuggestionsRequestLocked(@NonNull AutofillId autofillId,
@@ -72,16 +76,16 @@
// TODO(b/151123764): rename the method to better reflect what it does.
if (mSession != null) {
// Send an empty response to IME and destroy the existing session.
- mSession.onInlineSuggestionsResponseLocked(mSession.getAutofillIdLocked(),
- new InlineSuggestionsResponse(Collections.EMPTY_LIST));
+ mSession.onInlineSuggestionsResponseLocked(
+ InlineFillUi.emptyUi(mSession.getAutofillIdLocked()));
mSession.destroySessionLocked();
+ mInlineFillUi = null;
}
// TODO(b/151123764): consider reusing the same AutofillInlineSession object for the
// same field.
mSession = new AutofillInlineSuggestionsRequestSession(mInputMethodManagerInternal, mUserId,
mComponentName, mHandler, mLock, autofillId, requestConsumer, uiExtras);
mSession.onCreateInlineSuggestionsRequestLocked();
-
}
/**
@@ -101,30 +105,63 @@
/**
* Requests the IME to hide the current suggestions, if any. Returns true if the message is sent
- * to the IME.
+ * to the IME. This only hides the UI temporarily. For example if user starts typing/deleting
+ * characters, new filterText will kick in and may revive the suggestion UI.
*/
@GuardedBy("mLock")
boolean hideInlineSuggestionsUiLocked(@NonNull AutofillId autofillId) {
if (mSession != null) {
- return mSession.onInlineSuggestionsResponseLocked(autofillId,
- new InlineSuggestionsResponse(Collections.EMPTY_LIST));
+ return mSession.onInlineSuggestionsResponseLocked(InlineFillUi.emptyUi(autofillId));
}
return false;
}
/**
- * Requests showing the inline suggestion in the IME when the IME becomes visible and is focused
- * on the {@code autofillId}.
- *
- * @return false if there is no session, or if the IME callback is not available in the session.
+ * Permanently delete the current inline fill UI. Notify the IME to hide the suggestions as
+ * well.
*/
@GuardedBy("mLock")
- boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
- @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
- // TODO(b/151123764): rename the method to better reflect what it does.
- if (mSession != null) {
- return mSession.onInlineSuggestionsResponseLocked(autofillId,
- inlineSuggestionsResponse);
+ boolean deleteInlineFillUiLocked(@NonNull AutofillId autofillId) {
+ mInlineFillUi = null;
+ return hideInlineSuggestionsUiLocked(autofillId);
+ }
+
+ /**
+ * Updates the inline fill UI with the filter text. It'll send updated inline suggestions to
+ * the IME.
+ */
+ @GuardedBy("mLock")
+ boolean filterInlineFillUiLocked(@NonNull AutofillId autofillId, @Nullable String filterText) {
+ if (mInlineFillUi != null && mInlineFillUi.getAutofillId().equals(autofillId)) {
+ mInlineFillUi.setFilterText(filterText);
+ return requestImeToShowInlineSuggestionsLocked();
+ }
+ return false;
+ }
+
+ /**
+ * Set the current inline fill UI. It'll request the IME to show the inline suggestions when
+ * the IME becomes visible and is focused on the {@code autofillId}.
+ *
+ * @return false if the suggestions are not sent to IME because there is no session, or if the
+ * IME callback is not available in the session.
+ */
+ @GuardedBy("mLock")
+ boolean setInlineFillUiLocked(@NonNull InlineFillUi inlineFillUi) {
+ mInlineFillUi = inlineFillUi;
+ return requestImeToShowInlineSuggestionsLocked();
+ }
+
+ /**
+ * Sends the suggestions from the current inline fill UI to the IME.
+ *
+ * @return false if the suggestions are not sent to IME because there is no session, or if the
+ * IME callback is not available in the session.
+ */
+ @GuardedBy("mLock")
+ private boolean requestImeToShowInlineSuggestionsLocked() {
+ if (mSession != null && mInlineFillUi != null) {
+ return mSession.onInlineSuggestionsResponseLocked(mInlineFillUi);
}
return false;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index ce11c76..1a3baba 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -27,7 +27,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
@@ -37,6 +36,7 @@
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
+import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.lang.ref.WeakReference;
@@ -55,16 +55,6 @@
private static final String TAG = AutofillInlineSuggestionsRequestSession.class.getSimpleName();
- // This timeout controls how long Autofill should wait for the IME to respond either
- // unsupported or an {@link InlineSuggestionsRequest}. The timeout is needed to take into
- // account the latency between the two events after a field is focused, 1) an Autofill
- // request is triggered on framework; 2) the InputMethodService#onStartInput() event is
- // triggered on the IME side. When 1) happens, Autofill may call the IME to return an {@link
- // InlineSuggestionsRequest}, but the IME will only return it after 2) happens (or return
- // immediately if the IME doesn't support inline suggestions). Also there is IPC latency
- // between the framework and the IME but that should be small compare to that.
- private static final int CREATE_INLINE_SUGGESTIONS_REQUEST_TIMEOUT_MS = 1000;
-
@NonNull
private final InputMethodManagerInternal mInputMethodManagerInternal;
private final int mUserId;
@@ -92,9 +82,6 @@
@GuardedBy("mLock")
@Nullable
private IInlineSuggestionsResponseCallback mResponseCallback;
- @GuardedBy("mLock")
- @Nullable
- private Runnable mTimeoutCallback;
@GuardedBy("mLock")
@Nullable
@@ -105,7 +92,7 @@
private boolean mImeInputViewStarted;
@GuardedBy("mLock")
@Nullable
- private InlineSuggestionsResponse mInlineSuggestionsResponse;
+ private InlineFillUi mInlineFillUi;
@GuardedBy("mLock")
private boolean mPreviousResponseIsNotEmpty;
@@ -155,29 +142,36 @@
* @return false if the IME callback is not available.
*/
@GuardedBy("mLock")
- boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
- @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
+ boolean onInlineSuggestionsResponseLocked(@NonNull InlineFillUi inlineFillUi) {
if (mDestroyed) {
return false;
}
- if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked called for:" + autofillId);
+ if (sDebug) {
+ Slog.d(TAG,
+ "onInlineSuggestionsResponseLocked called for:" + inlineFillUi.getAutofillId());
+ }
if (mImeRequest == null || mResponseCallback == null) {
return false;
}
// TODO(b/151123764): each session should only correspond to one field.
- mAutofillId = autofillId;
- mInlineSuggestionsResponse = inlineSuggestionsResponse;
+ mAutofillId = inlineFillUi.getAutofillId();
+ mInlineFillUi = inlineFillUi;
maybeUpdateResponseToImeLocked();
return true;
}
/**
- * This method must be called when the session is destroyed, to avoid further callbacks from/to
- * the IME.
+ * Prevents further interaction with the IME. Must be called before starting a new request
+ * session to avoid unwanted behavior from two overlapping requests.
*/
@GuardedBy("mLock")
void destroySessionLocked() {
mDestroyed = true;
+
+ if (!mImeRequestReceived) {
+ Slog.w(TAG,
+ "Never received an InlineSuggestionsRequest from the IME for " + mAutofillId);
+ }
}
/**
@@ -190,15 +184,10 @@
if (mDestroyed) {
return;
}
- if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
+ if (sDebug) Slog.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
new InlineSuggestionsRequestCallbackImpl(this));
- mTimeoutCallback = () -> {
- Log.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
- handleOnReceiveImeRequest(null, null);
- };
- mHandler.postDelayed(mTimeoutCallback, CREATE_INLINE_SUGGESTIONS_REQUEST_TIMEOUT_MS);
}
/**
@@ -206,28 +195,29 @@
*/
@GuardedBy("mLock")
private void maybeUpdateResponseToImeLocked() {
- if (sVerbose) Log.v(TAG, "maybeUpdateResponseToImeLocked called");
+ if (sVerbose) Slog.v(TAG, "maybeUpdateResponseToImeLocked called");
if (mDestroyed || mResponseCallback == null) {
return;
}
- if (!mImeInputViewStarted && mPreviousResponseIsNotEmpty) {
- // 1. if previous response is not empty, and IME just become invisible, then send
- // empty response to make sure existing responses don't stick around on the IME.
+ if (!mImeInputStarted && mPreviousResponseIsNotEmpty) {
+ // 1. if previous response is not empty, and IME is just disconnected from the view,
+ // then send empty response to make sure existing responses don't stick around.
// Although the inline suggestions should disappear when IME hides which removes them
- // from the view hierarchy, but we still send an empty response to be extra safe.
-
- if (sVerbose) Log.v(TAG, "Send empty inline response");
+ // from the view hierarchy, but we still send an empty response to indicate that the
+ // previous suggestions are invalid now.
+ if (sVerbose) Slog.v(TAG, "Send empty inline response");
updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST));
mPreviousResponseIsNotEmpty = false;
- } else if (mImeInputViewStarted && mInlineSuggestionsResponse != null && match(mAutofillId,
+ } else if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
mImeCurrentFieldId)) {
// 2. if IME is visible, and response is not null, send the response
- boolean isEmptyResponse = mInlineSuggestionsResponse.getInlineSuggestions().isEmpty();
+ InlineSuggestionsResponse response = mInlineFillUi.getInlineSuggestionsResponse();
+ boolean isEmptyResponse = response.getInlineSuggestions().isEmpty();
if (isEmptyResponse && !mPreviousResponseIsNotEmpty) {
// No-op if both the previous response and current response are empty.
return;
}
- updateResponseToImeUncheckLocked(mInlineSuggestionsResponse);
+ updateResponseToImeUncheckLocked(response);
mPreviousResponseIsNotEmpty = !isEmptyResponse;
}
}
@@ -240,7 +230,7 @@
if (mDestroyed) {
return;
}
- if (sDebug) Log.d(TAG, "Send inline response: " + response.getInlineSuggestions().size());
+ if (sDebug) Slog.d(TAG, "Send inline response: " + response.getInlineSuggestions().size());
try {
mResponseCallback.onInlineSuggestionsResponse(mAutofillId, response);
} catch (RemoteException e) {
@@ -261,11 +251,6 @@
}
mImeRequestReceived = true;
- if (mTimeoutCallback != null) {
- if (sVerbose) Log.v(TAG, "removing timeout callback");
- mHandler.removeCallbacks(mTimeoutCallback);
- mTimeoutCallback = null;
- }
if (request != null && callback != null) {
mImeRequest = request;
mResponseCallback = callback;
@@ -333,7 +318,7 @@
@BinderThread
@Override
public void onInlineSuggestionsUnsupported() throws RemoteException {
- if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
+ if (sDebug) Slog.d(TAG, "onInlineSuggestionsUnsupported() called.");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -346,7 +331,7 @@
@Override
public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
IInlineSuggestionsResponseCallback callback) {
- if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
+ if (sDebug) Slog.d(TAG, "onInlineSuggestionsRequest() received: " + request);
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -357,7 +342,7 @@
@Override
public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
- if (sVerbose) Log.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
+ if (sVerbose) Slog.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -369,14 +354,14 @@
@Override
public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
if (sVerbose) {
- Log.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
+ Slog.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
}
}
@BinderThread
@Override
public void onInputMethodStartInputView() {
- if (sVerbose) Log.v(TAG, "onInputMethodStartInputView() received");
+ if (sVerbose) Slog.v(TAG, "onInputMethodStartInputView() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -388,7 +373,7 @@
@BinderThread
@Override
public void onInputMethodFinishInputView() {
- if (sVerbose) Log.v(TAG, "onInputMethodFinishInputView() received");
+ if (sVerbose) Slog.v(TAG, "onInputMethodFinishInputView() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -399,7 +384,7 @@
@Override
public void onInputMethodFinishInput() throws RemoteException {
- if (sVerbose) Log.v(TAG, "onInputMethodFinishInput() received");
+ if (sVerbose) Slog.v(TAG, "onInputMethodFinishInput() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1bc026c..1aeb19b 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -260,7 +260,7 @@
if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
// Check if it's enabled for augmented autofill
- if (isAugmentedAutofillServiceAvailableLocked()
+ if (componentName != null && isAugmentedAutofillServiceAvailableLocked()
&& isWhitelistedForAugmentedAutofillLocked(componentName)) {
return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 6cec8d8..851e4cc 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -48,17 +48,15 @@
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.inputmethod.InlineSuggestionsRequest;
-import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
-import com.android.server.autofill.ui.InlineSuggestionFactory;
+import com.android.server.autofill.ui.InlineFillUi;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
@@ -149,7 +147,7 @@
int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue,
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
- @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
+ @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
@NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
long requestTime = SystemClock.elapsedRealtime();
@@ -173,7 +171,8 @@
mCallbacks.resetLastResponse();
maybeRequestShowInlineSuggestions(sessionId,
inlineSuggestionsRequest, inlineSuggestionsData,
- clientState, focusedId, inlineSuggestionsCallback,
+ clientState, focusedId, focusedValue,
+ inlineSuggestionsCallback,
client, onErrorCallback, remoteRenderService);
requestAutofill.complete(null);
}
@@ -239,8 +238,8 @@
private void maybeRequestShowInlineSuggestions(int sessionId,
@Nullable InlineSuggestionsRequest request,
@Nullable List<Dataset> inlineSuggestionsData, @Nullable Bundle clientState,
- @NonNull AutofillId focusedId,
- @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
+ @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue,
+ @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
@NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
@@ -250,10 +249,14 @@
}
mCallbacks.setLastResponse(sessionId);
- final InlineSuggestionsResponse inlineSuggestionsResponse =
- InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
- request, inlineSuggestionsData, focusedId,
- new InlineSuggestionFactory.InlineSuggestionUiCallback() {
+ final String filterText =
+ focusedValue != null && focusedValue.isText()
+ ? focusedValue.getTextValue().toString() : null;
+
+ final InlineFillUi inlineFillUi =
+ InlineFillUi.forAugmentedAutofill(
+ request, inlineSuggestionsData, focusedId, filterText,
+ new InlineFillUi.InlineSuggestionUiCallback() {
@Override
public void autofill(Dataset dataset) {
mCallbacks.logAugmentedAutofillSelected(sessionId,
@@ -265,8 +268,8 @@
&& fieldIds.get(0).equals(focusedId);
client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
hideHighlight);
- inlineSuggestionsCallback.apply(new InlineSuggestionsResponse(
- Collections.EMPTY_LIST));
+ inlineSuggestionsCallback.apply(
+ InlineFillUi.emptyUi(focusedId));
} catch (RemoteException e) {
Slog.w(TAG, "Encounter exception autofilling the values");
}
@@ -283,11 +286,7 @@
}
}, onErrorCallback, remoteRenderService);
- if (inlineSuggestionsResponse == null) {
- Slog.w(TAG, "InlineSuggestionFactory created null response");
- return;
- }
- if (inlineSuggestionsCallback.apply(inlineSuggestionsResponse)) {
+ if (inlineSuggestionsCallback.apply(inlineFillUi)) {
mCallbacks.logAugmentedAutofillShown(sessionId, clientState);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
index 255adcd..617c111 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
@@ -47,7 +47,7 @@
private static final String TAG = "RemoteInlineSuggestionRenderService";
- private final int mIdleUnbindTimeoutMs = 5000;
+ private final long mIdleUnbindTimeoutMs = PERMANENT_BOUND_TIMEOUT_MS;
RemoteInlineSuggestionRenderService(Context context, ComponentName componentName,
String serviceInterface, int userId, InlineSuggestionRenderCallbacks callback,
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 20d1b98..1d3ab9b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -19,6 +19,7 @@
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
+import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
@@ -94,7 +95,6 @@
import android.view.autofill.IAutoFillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
import android.view.inputmethod.InlineSuggestionsRequest;
-import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -102,7 +102,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.server.autofill.ui.AutoFillUI;
-import com.android.server.autofill.ui.InlineSuggestionFactory;
+import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.autofill.ui.PendingUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -654,6 +654,10 @@
return mService.isInlineSuggestionsEnabled();
}
+ private boolean isViewFocusedLocked(int flags) {
+ return (flags & FLAG_VIEW_NOT_FOCUSED) == 0;
+ }
+
/**
* Clears the existing response for the partition, reads a new structure, and then requests a
* new fill response from the fill service.
@@ -712,10 +716,13 @@
cancelCurrentRequestLocked();
// Only ask IME to create inline suggestions request if Autofill provider supports it and
- // the render service is available.
+ // the render service is available except the autofill is triggered manually and the view
+ // is also not focused.
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
- if (isInlineSuggestionsEnabledByAutofillProviderLocked() && remoteRenderService != null) {
+ if (isInlineSuggestionsEnabledByAutofillProviderLocked()
+ && remoteRenderService != null
+ && isViewFocusedLocked(flags)) {
Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
mAssistReceiver.newAutofillRequestLocked(viewState,
/*isInlineRequest=*/ true);
@@ -2375,9 +2382,9 @@
@GuardedBy("mLock")
private boolean shouldStartNewPartitionLocked(@NonNull AutofillId id) {
final ViewState currentView = mViewStates.get(id);
- if (mResponses == null && currentView != null
- && (currentView.getState() & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) == 0) {
- return true;
+ if (mResponses == null) {
+ return currentView != null && (currentView.getState()
+ & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) == 0;
}
if (mExpiredResponse) {
@@ -2574,7 +2581,6 @@
if (sVerbose) Slog.v(TAG, "Exiting view " + id);
mUi.hideFillUi(this);
hideAugmentedAutofillLocked(viewState);
- mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
mCurrentViewId = null;
}
break;
@@ -2648,6 +2654,9 @@
if (sVerbose) {
Slog.v(TAG, "ignoring autofilled change on id " + id);
}
+ // TODO(b/156099633): remove this once framework gets out of business of resending
+ // inline suggestions when IME visibility changes.
+ mInlineSessionController.hideInlineSuggestionsUiLocked(viewState.id);
viewState.resetState(ViewState.STATE_CHANGED);
return;
} else if ((viewState.id.equals(this.mCurrentViewId))
@@ -2662,10 +2671,20 @@
}
} else if (viewState.id.equals(this.mCurrentViewId)
&& (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
- requestShowInlineSuggestionsLocked(viewState.getResponse(), filterText);
+ if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
+ final FillResponse response = viewState.getResponse();
+ if (response != null) {
+ response.getDatasets().clear();
+ }
+ mInlineSessionController.deleteInlineFillUiLocked(viewState.id);
+ } else {
+ mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
+ }
} else if (viewState.id.equals(this.mCurrentViewId)
&& (viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
if (!TextUtils.isEmpty(filterText)) {
+ // TODO: we should be able to replace this with controller#filterInlineFillUiLocked
+ // to accomplish filtering for augmented autofill.
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
}
}
@@ -2816,26 +2835,15 @@
return false;
}
- final ViewState currentView = mViewStates.get(focusedId);
- if ((currentView.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
- response.getDatasets().clear();
- }
- InlineSuggestionsResponse inlineSuggestionsResponse =
- InlineSuggestionFactory.createInlineSuggestionsResponse(
- inlineSuggestionsRequest.get(), response, filterText, focusedId,
- this, () -> {
- synchronized (mLock) {
- mInlineSessionController.hideInlineSuggestionsUiLocked(
- focusedId);
- }
- }, remoteRenderService);
- if (inlineSuggestionsResponse == null) {
- Slog.w(TAG, "InlineSuggestionFactory created null response");
- return false;
- }
-
- return mInlineSessionController.onInlineSuggestionsResponseLocked(focusedId,
- inlineSuggestionsResponse);
+ InlineFillUi inlineFillUi = InlineFillUi.forAutofill(
+ inlineSuggestionsRequest.get(), response, focusedId, filterText,
+ /*uiCallback*/this, /*onErrorCallback*/ () -> {
+ synchronized (mLock) {
+ mInlineSessionController.hideInlineSuggestionsUiLocked(
+ focusedId);
+ }
+ }, remoteRenderService);
+ return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
}
boolean isDestroyed() {
@@ -3119,11 +3127,10 @@
final AutofillId focusedId = mCurrentViewId;
- final Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsResponseCallback =
+ final Function<InlineFillUi, Boolean> inlineSuggestionsResponseCallback =
response -> {
synchronized (mLock) {
- return mInlineSessionController.onInlineSuggestionsResponseLocked(
- focusedId, response);
+ return mInlineSessionController.setInlineFillUiLocked(response);
}
};
final Consumer<InlineSuggestionsRequest> requestAugmentedAutofill =
@@ -3142,9 +3149,9 @@
}
};
- // When the inline suggestion render service is available, there are 2 cases when
- // augmented autofill should ask IME for inline suggestion request, because standard
- // autofill flow didn't:
+ // When the inline suggestion render service is available and the view is focused, there
+ // are 2 cases when augmented autofill should ask IME for inline suggestion request,
+ // because standard autofill flow didn't:
// 1. the field is augmented autofill only (when standard autofill provider is None or
// when it returns null response)
// 2. standard autofill provider doesn't support inline suggestion
@@ -3152,7 +3159,8 @@
mService.getRemoteInlineSuggestionRenderServiceLocked();
if (remoteRenderService != null
&& (mForAugmentedAutofillOnly
- || !isInlineSuggestionsEnabledByAutofillProviderLocked())) {
+ || !isInlineSuggestionsEnabledByAutofillProviderLocked())
+ && isViewFocusedLocked(flags)) {
if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
remoteRenderService.getInlineSuggestionsRendererInfo(new RemoteCallback(
(extras) -> {
@@ -3342,7 +3350,9 @@
if (generateEvent) {
mService.logDatasetSelected(dataset.getId(), id, mClientState);
}
-
+ if (mCurrentViewId != null) {
+ mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
+ }
autoFillApp(dataset);
return;
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 344b92f..8902087 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -130,9 +130,9 @@
}
FillUi(@NonNull Context context, @NonNull FillResponse response,
- @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
- @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
- @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
+ @NonNull AutofillId focusedViewId, @Nullable String filterText,
+ @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
+ @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
mCallback = callback;
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java b/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java
new file mode 100644
index 0000000..7fbf4b9
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * 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.autofill.ui;
+
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.util.Slog;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.FgThread;
+
+/**
+ * We create one instance of this class for each {@link android.view.inputmethod.InlineSuggestion}
+ * instance. Each inline suggestion instance will only be sent to the remote IME process once. In
+ * case of filtering and resending the suggestion when keyboard state changes between hide and
+ * show, a new instance of this class will be created using {@link #copy()}, with the same backing
+ * {@link RemoteInlineSuggestionUi}. When the
+ * {@link #provideContent(int, int, IInlineContentCallback)} is called the first time (it's only
+ * allowed to be called at most once), the passed in width/height is used to determine whether
+ * the existing {@link RemoteInlineSuggestionUi} provided in the constructor can be reused, or a
+ * new one should be created to suit the new size requirement for the view. In normal cases,
+ * we should not expect the size requirement to change, although in theory the public API allows
+ * the IME to do that.
+ *
+ * <p>This design is to enable us to be able to reuse the backing remote view while still keeping
+ * the callbacks relatively well aligned. For example, if we allow multiple remote IME binder
+ * callbacks to call into one instance of this class, then binder A may call in with width/height
+ * X for which we create a view (i.e. {@link RemoteInlineSuggestionUi}) for it,
+ *
+ * See also {@link RemoteInlineSuggestionUi} for relevant information.
+ */
+final class InlineContentProviderImpl extends IInlineContentProvider.Stub {
+
+ // TODO(b/153615023): consider not holding strong reference to heavy objects in this stub, to
+ // avoid memory leak in case the client app is holding the remote reference for a longer
+ // time than expected. Essentially we need strong reference in the system process to
+ // the member variables, but weak reference to them in the IInlineContentProvider.Stub.
+
+ private static final String TAG = InlineContentProviderImpl.class.getSimpleName();
+
+ private final Handler mHandler = FgThread.getHandler();;
+
+ @NonNull
+ private final RemoteInlineSuggestionViewConnector mRemoteInlineSuggestionViewConnector;
+ @Nullable
+ private RemoteInlineSuggestionUi mRemoteInlineSuggestionUi;
+
+ private boolean mProvideContentCalled = false;
+
+ InlineContentProviderImpl(
+ @NonNull RemoteInlineSuggestionViewConnector remoteInlineSuggestionViewConnector,
+ @Nullable RemoteInlineSuggestionUi remoteInlineSuggestionUi) {
+ mRemoteInlineSuggestionViewConnector = remoteInlineSuggestionViewConnector;
+ mRemoteInlineSuggestionUi = remoteInlineSuggestionUi;
+ }
+
+ /**
+ * Returns a new instance of this class, with the same {@code mInlineSuggestionRenderer} and
+ * {@code mRemoteInlineSuggestionUi}. The latter may or may not be reusable depending on the
+ * size information provided when the client calls {@link #provideContent(int, int,
+ * IInlineContentCallback)}.
+ */
+ @NonNull
+ public InlineContentProviderImpl copy() {
+ return new InlineContentProviderImpl(mRemoteInlineSuggestionViewConnector,
+ mRemoteInlineSuggestionUi);
+ }
+
+ /**
+ * Provides a SurfacePackage associated with the inline suggestion view to the IME. If such
+ * view doesn't exit, then create a new one. This method should be called once per lifecycle
+ * of this object. Any further calls to the method will be ignored.
+ */
+ @Override
+ public void provideContent(int width, int height, IInlineContentCallback callback) {
+ mHandler.post(() -> handleProvideContent(width, height, callback));
+ }
+
+ @Override
+ public void requestSurfacePackage() {
+ mHandler.post(this::handleGetSurfacePackage);
+ }
+
+ @Override
+ public void onSurfacePackageReleased() {
+ mHandler.post(this::handleOnSurfacePackageReleased);
+ }
+
+ private void handleProvideContent(int width, int height, IInlineContentCallback callback) {
+ if (sVerbose) Slog.v(TAG, "handleProvideContent");
+ if (mProvideContentCalled) {
+ // This method should only be called once.
+ return;
+ }
+ mProvideContentCalled = true;
+ if (mRemoteInlineSuggestionUi == null || !mRemoteInlineSuggestionUi.match(width, height)) {
+ mRemoteInlineSuggestionUi = new RemoteInlineSuggestionUi(
+ mRemoteInlineSuggestionViewConnector,
+ width, height, mHandler);
+ }
+ mRemoteInlineSuggestionUi.setInlineContentCallback(callback);
+ mRemoteInlineSuggestionUi.requestSurfacePackage();
+ }
+
+ private void handleGetSurfacePackage() {
+ if (sVerbose) Slog.v(TAG, "handleGetSurfacePackage");
+ if (!mProvideContentCalled || mRemoteInlineSuggestionUi == null) {
+ // provideContent should be called first, and remote UI should not be null.
+ return;
+ }
+ mRemoteInlineSuggestionUi.requestSurfacePackage();
+ }
+
+ private void handleOnSurfacePackageReleased() {
+ if (sVerbose) Slog.v(TAG, "handleOnSurfacePackageReleased");
+ if (!mProvideContentCalled || mRemoteInlineSuggestionUi == null) {
+ // provideContent should be called first, and remote UI should not be null.
+ return;
+ }
+ mRemoteInlineSuggestionUi.surfacePackageReleased();
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
new file mode 100644
index 0000000..6522522
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -0,0 +1,282 @@
+/*
+ * 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.autofill.ui;
+
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.service.autofill.InlinePresentation;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.inputmethod.InlineSuggestion;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
+
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.autofill.RemoteInlineSuggestionRenderService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+
+/**
+ * UI for a particular field (i.e. {@link AutofillId}) based on an inline autofill response from
+ * the autofill service or the augmented autofill service. It wraps multiple inline suggestions.
+ *
+ * <p> This class is responsible for filtering the suggestions based on the filtered text.
+ * It'll create {@link InlineSuggestion} instances by reusing the backing remote views (from the
+ * renderer service) if possible.
+ */
+public final class InlineFillUi {
+
+ private static final String TAG = "InlineFillUi";
+
+ /**
+ * The id of the field which the current Ui is for.
+ */
+ @NonNull
+ final AutofillId mAutofillId;
+
+ /**
+ * The list of inline suggestions, before applying any filtering
+ */
+ @NonNull
+ private final ArrayList<InlineSuggestion> mInlineSuggestions;
+
+ /**
+ * The corresponding data sets for the inline suggestions. The list may be null if the current
+ * Ui is the authentication UI for the response. If non-null, the size of data sets should equal
+ * that of inline suggestions.
+ */
+ @Nullable
+ private final ArrayList<Dataset> mDatasets;
+
+ /**
+ * The filter text which will be applied on the inline suggestion list before they are returned
+ * as a response.
+ */
+ @Nullable
+ private String mFilterText;
+
+ /**
+ * Returns an empty inline autofill UI.
+ */
+ @NonNull
+ public static InlineFillUi emptyUi(@NonNull AutofillId autofillId) {
+ return new InlineFillUi(autofillId, new SparseArray<>(), null);
+ }
+
+ /**
+ * Returns an inline autofill UI for a field based on an Autofilll response.
+ */
+ @NonNull
+ public static InlineFillUi forAutofill(@NonNull InlineSuggestionsRequest request,
+ @NonNull FillResponse response,
+ @NonNull AutofillId focusedViewId, @Nullable String filterText,
+ @NonNull AutoFillUI.AutoFillUiCallback uiCallback,
+ @NonNull Runnable onErrorCallback,
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+
+ if (InlineSuggestionFactory.responseNeedAuthentication(response)) {
+ InlineSuggestion inlineAuthentication =
+ InlineSuggestionFactory.createInlineAuthentication(request, response,
+ focusedViewId, uiCallback, onErrorCallback, remoteRenderService);
+ return new InlineFillUi(focusedViewId, inlineAuthentication, filterText);
+ } else if (response.getDatasets() != null) {
+ SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
+ InlineSuggestionFactory.createAutofillInlineSuggestions(request,
+ response.getRequestId(),
+ response.getDatasets(), focusedViewId, uiCallback, onErrorCallback,
+ remoteRenderService);
+ return new InlineFillUi(focusedViewId, inlineSuggestions, filterText);
+ }
+ return new InlineFillUi(focusedViewId, new SparseArray<>(), filterText);
+ }
+
+ /**
+ * Returns an inline autofill UI for a field based on an Autofilll response.
+ */
+ @NonNull
+ public static InlineFillUi forAugmentedAutofill(@NonNull InlineSuggestionsRequest request,
+ @NonNull List<Dataset> datasets,
+ @NonNull AutofillId focusedViewId, @Nullable String filterText,
+ @NonNull InlineSuggestionUiCallback uiCallback,
+ @NonNull Runnable onErrorCallback,
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+ SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
+ InlineSuggestionFactory.createAugmentedAutofillInlineSuggestions(request, datasets,
+ focusedViewId,
+ uiCallback, onErrorCallback, remoteRenderService);
+ return new InlineFillUi(focusedViewId, inlineSuggestions, filterText);
+ }
+
+ InlineFillUi(@NonNull AutofillId autofillId,
+ @NonNull SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions,
+ @Nullable String filterText) {
+ mAutofillId = autofillId;
+ int size = inlineSuggestions.size();
+ mDatasets = new ArrayList<>(size);
+ mInlineSuggestions = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ Pair<Dataset, InlineSuggestion> value = inlineSuggestions.valueAt(i);
+ mDatasets.add(value.first);
+ mInlineSuggestions.add(value.second);
+ }
+ mFilterText = filterText;
+ }
+
+ InlineFillUi(@NonNull AutofillId autofillId, InlineSuggestion inlineSuggestion,
+ @Nullable String filterText) {
+ mAutofillId = autofillId;
+ mDatasets = null;
+ mInlineSuggestions = new ArrayList<>();
+ mInlineSuggestions.add(inlineSuggestion);
+ mFilterText = filterText;
+ }
+
+ @NonNull
+ public AutofillId getAutofillId() {
+ return mAutofillId;
+ }
+
+ public void setFilterText(@Nullable String filterText) {
+ mFilterText = filterText;
+ }
+
+ /**
+ * Returns the list of filtered inline suggestions suitable for being sent to the IME.
+ */
+ @NonNull
+ public InlineSuggestionsResponse getInlineSuggestionsResponse() {
+ final int size = mInlineSuggestions.size();
+ if (size == 0) {
+ return new InlineSuggestionsResponse(Collections.emptyList());
+ }
+ final List<InlineSuggestion> inlineSuggestions = new ArrayList<>();
+ if (mDatasets == null || mDatasets.size() != size) {
+ // authentication case
+ for (int i = 0; i < size; i++) {
+ inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
+ }
+ return new InlineSuggestionsResponse(inlineSuggestions);
+ }
+ for (int i = 0; i < size; i++) {
+ final Dataset dataset = mDatasets.get(i);
+ final int fieldIndex = dataset.getFieldIds().indexOf(mAutofillId);
+ if (fieldIndex < 0) {
+ Slog.w(TAG, "AutofillId=" + mAutofillId + " not found in dataset");
+ continue;
+ }
+ final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation(
+ fieldIndex);
+ if (inlinePresentation == null) {
+ Slog.w(TAG, "InlinePresentation not found in dataset");
+ continue;
+ }
+ if (!inlinePresentation.isPinned() // don't filter pinned suggestions
+ && !includeDataset(dataset, fieldIndex, mFilterText)) {
+ continue;
+ }
+ inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
+ }
+ return new InlineSuggestionsResponse(inlineSuggestions);
+ }
+
+ /**
+ * Returns a copy of the suggestion, that internally copies the {@link IInlineContentProvider}
+ * so that it's not reused by the remote IME process across different inline suggestions.
+ * See {@link InlineContentProviderImpl} for why this is needed.
+ *
+ * <p>Note that although it copies the {@link IInlineContentProvider}, the underlying remote
+ * view (in the renderer service) is still reused.
+ */
+ @NonNull
+ private InlineSuggestion copy(int index, @NonNull InlineSuggestion inlineSuggestion) {
+ final IInlineContentProvider contentProvider = inlineSuggestion.getContentProvider();
+ if (contentProvider instanceof InlineContentProviderImpl) {
+ // We have to create a new inline suggestion instance to ensure we don't reuse the
+ // same {@link IInlineContentProvider}, but the underlying views are reused when
+ // calling {@link InlineContentProviderImpl#copy()}.
+ InlineSuggestion newInlineSuggestion = new InlineSuggestion(inlineSuggestion
+ .getInfo(), ((InlineContentProviderImpl) contentProvider).copy());
+ // The remote view is only set when the content provider is called to inflate the view,
+ // which happens after it's sent to the IME (i.e. not now), so we keep the latest
+ // content provider (through newInlineSuggestion) to make sure the next time we copy it,
+ // we get to reuse the view.
+ mInlineSuggestions.set(index, newInlineSuggestion);
+ return newInlineSuggestion;
+ }
+ return inlineSuggestion;
+ }
+
+ // TODO: Extract the shared filtering logic here and in FillUi to a common method.
+ private static boolean includeDataset(Dataset dataset, int fieldIndex,
+ @Nullable String filterText) {
+ // Show everything when the user input is empty.
+ if (TextUtils.isEmpty(filterText)) {
+ return true;
+ }
+
+ final String constraintLowerCase = filterText.toString().toLowerCase();
+
+ // Use the filter provided by the service, if available.
+ final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
+ if (filter != null) {
+ Pattern filterPattern = filter.pattern;
+ if (filterPattern == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
+ }
+ return true;
+ }
+ return filterPattern.matcher(constraintLowerCase).matches();
+ }
+
+ final AutofillValue value = dataset.getFieldValues().get(fieldIndex);
+ if (value == null || !value.isText()) {
+ return dataset.getAuthentication() != null;
+ }
+ final String valueText = value.getTextValue().toString().toLowerCase();
+ return valueText.toLowerCase().startsWith(constraintLowerCase);
+ }
+
+ /**
+ * Callback from the inline suggestion Ui.
+ */
+ public interface InlineSuggestionUiCallback {
+ /**
+ * Callback to autofill a dataset to the client app.
+ */
+ void autofill(@NonNull Dataset dataset);
+
+ /**
+ * Callback to start Intent in client app.
+ */
+ void startIntentSender(@NonNull IntentSender intentSender, @NonNull Intent intent);
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 79c9efa..c8485b7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -17,59 +17,57 @@
package com.android.server.autofill.ui;
import static com.android.server.autofill.Helper.sDebug;
-import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.IntentSender;
import android.os.IBinder;
-import android.os.RemoteException;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
-import android.service.autofill.IInlineSuggestionUiCallback;
import android.service.autofill.InlinePresentation;
-import android.text.TextUtils;
+import android.util.Pair;
import android.util.Slog;
-import android.view.SurfaceControlViewHost;
+import android.util.SparseArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionInfo;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;
import android.widget.inline.InlinePresentationSpec;
-import com.android.internal.view.inline.IInlineContentCallback;
import com.android.internal.view.inline.IInlineContentProvider;
-import com.android.server.LocalServices;
-import com.android.server.UiThread;
import com.android.server.autofill.RemoteInlineSuggestionRenderService;
-import com.android.server.inputmethod.InputMethodManagerInternal;
-import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
-import java.util.regex.Pattern;
-public final class InlineSuggestionFactory {
+final class InlineSuggestionFactory {
private static final String TAG = "InlineSuggestionFactory";
- /**
- * Callback from the inline suggestion Ui.
- */
- public interface InlineSuggestionUiCallback {
- /**
- * Callback to autofill a dataset to the client app.
- */
- void autofill(@NonNull Dataset dataset);
+ public static boolean responseNeedAuthentication(@NonNull FillResponse response) {
+ return response.getAuthentication() != null && response.getInlinePresentation() != null;
+ }
- /**
- * Callback to start Intent in client app.
- */
- void startIntentSender(@NonNull IntentSender intentSender, @NonNull Intent intent);
+ public static InlineSuggestion createInlineAuthentication(
+ @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
+ @NonNull AutofillId autofillId,
+ @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+ final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
+ client.authenticate(response.getRequestId(),
+ datasetIndex, response.getAuthentication(), response.getClientState(),
+ /* authenticateInline= */ true);
+ };
+ final Consumer<IntentSender> intentSenderConsumer = (intentSender) ->
+ client.startIntentSender(intentSender, new Intent());
+ InlinePresentation inlineAuthentication = response.getInlinePresentation();
+ return createInlineAuthSuggestion(
+ mergedInlinePresentation(request, 0, inlineAuthentication),
+ remoteRenderService, onClickFactory, onErrorCallback, intentSenderConsumer,
+ request.getHostInputToken(), request.getHostDisplayId());
}
/**
@@ -77,33 +75,22 @@
* autofill service, potentially filtering the datasets.
*/
@Nullable
- public static InlineSuggestionsResponse createInlineSuggestionsResponse(
- @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
- @Nullable String filterText, @NonNull AutofillId autofillId,
+ public static SparseArray<Pair<Dataset, InlineSuggestion>> createAutofillInlineSuggestions(
+ @NonNull InlineSuggestionsRequest request, int requestId,
+ @NonNull List<Dataset> datasets,
+ @NonNull AutofillId autofillId,
@NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
- final BiConsumer<Dataset, Integer> onClickFactory;
- if (response.getAuthentication() != null) {
- onClickFactory = (dataset, datasetIndex) -> {
- client.requestHideFillUi(autofillId);
- client.authenticate(response.getRequestId(),
- datasetIndex, response.getAuthentication(), response.getClientState(),
- /* authenticateInline= */ true);
- };
- } else {
- onClickFactory = (dataset, datasetIndex) -> {
- client.requestHideFillUi(autofillId);
- client.fill(response.getRequestId(), datasetIndex, dataset);
- };
- }
+ final Consumer<IntentSender> intentSenderConsumer = (intentSender) ->
+ client.startIntentSender(intentSender, new Intent());
+ final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
+ client.fill(requestId, datasetIndex, dataset);
+ };
- final InlinePresentation inlineAuthentication =
- response.getAuthentication() == null ? null : response.getInlinePresentation();
- return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
- response.getDatasets(), filterText, inlineAuthentication, autofillId,
- onErrorCallback, onClickFactory, (intentSender) ->
- client.startIntentSender(intentSender, new Intent()), remoteRenderService);
+ return createInlineSuggestionsInternal(/* isAugmented= */ false, request,
+ datasets, autofillId,
+ onErrorCallback, onClickFactory, intentSenderConsumer, remoteRenderService);
}
/**
@@ -111,16 +98,16 @@
* autofill service.
*/
@Nullable
- public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
+ public static SparseArray<Pair<Dataset, InlineSuggestion>>
+ createAugmentedAutofillInlineSuggestions(
@NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets,
@NonNull AutofillId autofillId,
- @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
+ @NonNull InlineFillUi.InlineSuggestionUiCallback inlineSuggestionUiCallback,
@NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
- return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
- datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
- autofillId, onErrorCallback,
+ return createInlineSuggestionsInternal(/* isAugmented= */ true, request,
+ datasets, autofillId, onErrorCallback,
(dataset, datasetIndex) ->
inlineSuggestionUiCallback.autofill(dataset),
(intentSender) ->
@@ -129,29 +116,13 @@
}
@Nullable
- private static InlineSuggestionsResponse createInlineSuggestionsResponseInternal(
+ private static SparseArray<Pair<Dataset, InlineSuggestion>> createInlineSuggestionsInternal(
boolean isAugmented, @NonNull InlineSuggestionsRequest request,
- @Nullable List<Dataset> datasets, @Nullable String filterText,
- @Nullable InlinePresentation inlineAuthentication, @NonNull AutofillId autofillId,
+ @NonNull List<Dataset> datasets, @NonNull AutofillId autofillId,
@NonNull Runnable onErrorCallback, @NonNull BiConsumer<Dataset, Integer> onClickFactory,
@NonNull Consumer<IntentSender> intentSenderConsumer,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
-
- final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
- if (inlineAuthentication != null) {
- InlineSuggestion inlineAuthSuggestion = createInlineAuthSuggestion(inlineAuthentication,
- remoteRenderService, onClickFactory, onErrorCallback, intentSenderConsumer,
- request.getHostInputToken(), request.getHostDisplayId());
- inlineSuggestions.add(inlineAuthSuggestion);
-
- return new InlineSuggestionsResponse(inlineSuggestions);
- }
-
- if (datasets == null) {
- Slog.w(TAG, "Datasets should not be null here");
- return null;
- }
-
+ SparseArray<Pair<Dataset, InlineSuggestion>> response = new SparseArray<>(datasets.size());
for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) {
final Dataset dataset = datasets.get(datasetIndex);
final int fieldIndex = dataset.getFieldIds().indexOf(autofillId);
@@ -165,50 +136,14 @@
Slog.w(TAG, "InlinePresentation not found in dataset");
continue;
}
- if (!inlinePresentation.isPinned() // don't filter pinned suggestions
- && !includeDataset(dataset, fieldIndex, filterText)) {
- continue;
- }
InlineSuggestion inlineSuggestion = createInlineSuggestion(isAugmented, dataset,
datasetIndex,
mergedInlinePresentation(request, datasetIndex, inlinePresentation),
onClickFactory, remoteRenderService, onErrorCallback, intentSenderConsumer,
request.getHostInputToken(), request.getHostDisplayId());
-
- inlineSuggestions.add(inlineSuggestion);
+ response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
}
- return new InlineSuggestionsResponse(inlineSuggestions);
- }
-
- // TODO: Extract the shared filtering logic here and in FillUi to a common method.
- private static boolean includeDataset(Dataset dataset, int fieldIndex,
- @Nullable String filterText) {
- // Show everything when the user input is empty.
- if (TextUtils.isEmpty(filterText)) {
- return true;
- }
-
- final String constraintLowerCase = filterText.toString().toLowerCase();
-
- // Use the filter provided by the service, if available.
- final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
- if (filter != null) {
- Pattern filterPattern = filter.pattern;
- if (filterPattern == null) {
- if (sVerbose) {
- Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
- }
- return true;
- }
- return filterPattern.matcher(constraintLowerCase).matches();
- }
-
- final AutofillValue value = dataset.getFieldValues().get(fieldIndex);
- if (value == null || !value.isText()) {
- return dataset.getAuthentication() == null;
- }
- final String valueText = value.getTextValue().toString().toLowerCase();
- return valueText.toLowerCase().startsWith(constraintLowerCase);
+ return response;
}
private static InlineSuggestion createInlineSuggestion(boolean isAugmented,
@@ -276,78 +211,20 @@
inlinePresentation.isPinned());
}
- private static IInlineContentProvider.Stub createInlineContentProvider(
+ private static IInlineContentProvider createInlineContentProvider(
@NonNull InlinePresentation inlinePresentation, @Nullable Runnable onClickAction,
@NonNull Runnable onErrorCallback,
@NonNull Consumer<IntentSender> intentSenderConsumer,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService,
@Nullable IBinder hostInputToken,
int displayId) {
- return new IInlineContentProvider.Stub() {
- @Override
- public void provideContent(int width, int height, IInlineContentCallback callback) {
- UiThread.getHandler().post(() -> {
- final IInlineSuggestionUiCallback uiCallback = createInlineSuggestionUiCallback(
- callback, onClickAction, onErrorCallback, intentSenderConsumer);
-
- if (remoteRenderService == null) {
- Slog.e(TAG, "RemoteInlineSuggestionRenderService is null");
- return;
- }
-
- remoteRenderService.renderSuggestion(uiCallback, inlinePresentation,
- width, height, hostInputToken, displayId);
- });
- }
- };
- }
-
- private static IInlineSuggestionUiCallback.Stub createInlineSuggestionUiCallback(
- @NonNull IInlineContentCallback callback, @NonNull Runnable onAutofillCallback,
- @NonNull Runnable onErrorCallback,
- @NonNull Consumer<IntentSender> intentSenderConsumer) {
- return new IInlineSuggestionUiCallback.Stub() {
- @Override
- public void onClick() throws RemoteException {
- onAutofillCallback.run();
- callback.onClick();
- }
-
- @Override
- public void onLongClick() throws RemoteException {
- callback.onLongClick();
- }
-
- @Override
- public void onContent(SurfaceControlViewHost.SurfacePackage surface, int width,
- int height)
- throws RemoteException {
- callback.onContent(surface, width, height);
- surface.release();
- }
-
- @Override
- public void onError() throws RemoteException {
- onErrorCallback.run();
- }
-
- @Override
- public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId)
- throws RemoteException {
- final InputMethodManagerInternal inputMethodManagerInternal =
- LocalServices.getService(InputMethodManagerInternal.class);
- if (!inputMethodManagerInternal.transferTouchFocusToImeWindow(sourceInputToken,
- displayId)) {
- Slog.e(TAG, "Cannot transfer touch focus from suggestion to IME");
- onErrorCallback.run();
- }
- }
-
- @Override
- public void onStartIntentSender(IntentSender intentSender) {
- intentSenderConsumer.accept(intentSender);
- }
- };
+ RemoteInlineSuggestionViewConnector
+ remoteInlineSuggestionViewConnector = new RemoteInlineSuggestionViewConnector(
+ remoteRenderService, inlinePresentation, hostInputToken, displayId, onClickAction,
+ onErrorCallback, intentSenderConsumer);
+ InlineContentProviderImpl inlineContentProvider = new InlineContentProviderImpl(
+ remoteInlineSuggestionViewConnector, null);
+ return inlineContentProvider;
}
private InlineSuggestionFactory() {
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java
new file mode 100644
index 0000000..368f717
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java
@@ -0,0 +1,300 @@
+/*
+ * 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.autofill.ui;
+
+import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentSender;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.autofill.IInlineSuggestionUi;
+import android.service.autofill.IInlineSuggestionUiCallback;
+import android.service.autofill.ISurfacePackageResultCallback;
+import android.util.Slog;
+import android.view.SurfaceControlViewHost;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+
+/**
+ * The instance of this class lives in the system server, orchestrating the communication between
+ * the remote process owning embedded view (i.e. ExtServices) and the remote process hosting the
+ * embedded view (i.e. IME). It's also responsible for releasing the embedded view from the owning
+ * process when it's not longer needed in the hosting process.
+ *
+ * <p>An instance of this class may be reused to associate with multiple instances of
+ * {@link InlineContentProviderImpl}s, each of which wraps a callback from the IME. But at any
+ * given time, there is only one active IME callback which this class will callback into.
+ *
+ * <p>This class is thread safe, because all the outside calls are piped into a single handler
+ * thread to be processed.
+ */
+final class RemoteInlineSuggestionUi {
+
+ private static final String TAG = RemoteInlineSuggestionUi.class.getSimpleName();
+
+ // The delay time to release the remote inline suggestion view (in the renderer
+ // process) after receiving a signal about the surface package being released due to being
+ // detached from the window in the host app (in the IME process). The release will be
+ // canceled if the host app reattaches the view to a window within this delay time.
+ // TODO(b/154683107): try out using the Chroreographer to schedule the release right at the
+ // next frame. Basically if the view is not re-attached to the window immediately in the next
+ // frame after it was detached, then it will be released.
+ private static final long RELEASE_REMOTE_VIEW_HOST_DELAY_MS = 200;
+
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final RemoteInlineSuggestionViewConnector mRemoteInlineSuggestionViewConnector;
+ private final int mWidth;
+ private final int mHeight;
+ @NonNull
+ private final InlineSuggestionUiCallbackImpl mInlineSuggestionUiCallback;
+
+ @Nullable
+ private IInlineContentCallback mInlineContentCallback; // from IME
+
+ /**
+ * Remote inline suggestion view, backed by an instance of {@link SurfaceControlViewHost} in
+ * the render service process. We takes care of releasing it when there is no remote
+ * reference to it (from IME), and we will create a new instance of the view when it's needed
+ * by IME again.
+ */
+ @Nullable
+ private IInlineSuggestionUi mInlineSuggestionUi;
+ private int mRefCount = 0;
+ private boolean mWaitingForUiCreation = false;
+ private int mActualWidth;
+ private int mActualHeight;
+
+ @Nullable
+ private Runnable mDelayedReleaseViewRunnable;
+
+ RemoteInlineSuggestionUi(
+ @NonNull RemoteInlineSuggestionViewConnector remoteInlineSuggestionViewConnector,
+ int width, int height, Handler handler) {
+ mHandler = handler;
+ mRemoteInlineSuggestionViewConnector = remoteInlineSuggestionViewConnector;
+ mWidth = width;
+ mHeight = height;
+ mInlineSuggestionUiCallback = new InlineSuggestionUiCallbackImpl();
+ }
+
+ /**
+ * Updates the callback from the IME process. It'll swap out the previous IME callback, and
+ * all the subsequent callback events (onClick, onLongClick, touch event transfer, etc) will
+ * be directed to the new callback.
+ */
+ void setInlineContentCallback(@NonNull IInlineContentCallback inlineContentCallback) {
+ mHandler.post(() -> {
+ mInlineContentCallback = inlineContentCallback;
+ });
+ }
+
+ /**
+ * Handles the request from the IME process to get a new surface package. May create a new
+ * view in the renderer process if the existing view is already released.
+ */
+ void requestSurfacePackage() {
+ mHandler.post(this::handleRequestSurfacePackage);
+ }
+
+ /**
+ * Handles the signal from the IME process that the previously sent surface package has been
+ * released.
+ */
+ void surfacePackageReleased() {
+ mHandler.post(() -> handleUpdateRefCount(-1));
+ }
+
+ /**
+ * Returns true if the provided size matches the remote view's size.
+ */
+ boolean match(int width, int height) {
+ return mWidth == width && mHeight == height;
+ }
+
+ private void handleRequestSurfacePackage() {
+ cancelPendingReleaseViewRequest();
+
+ if (mInlineSuggestionUi == null) {
+ if (mWaitingForUiCreation) {
+ // This could happen in the following case: the remote embedded view was released
+ // when previously detached from window. An event after that to re-attached to
+ // the window will cause us calling the renderSuggestion again. Now, before the
+ // render call returns a new surface package, if the view is detached and
+ // re-attached to the window, causing this method to be called again, we will get
+ // to this state. This request will be ignored and the surface package will still
+ // be sent back once the view is rendered.
+ if (sDebug) Slog.d(TAG, "Inline suggestion ui is not ready");
+ } else {
+ mRemoteInlineSuggestionViewConnector.renderSuggestion(mWidth, mHeight,
+ mInlineSuggestionUiCallback);
+ mWaitingForUiCreation = true;
+ }
+ } else {
+ try {
+ mInlineSuggestionUi.getSurfacePackage(new ISurfacePackageResultCallback.Stub() {
+ @Override
+ public void onResult(SurfaceControlViewHost.SurfacePackage result) {
+ mHandler.post(() -> {
+ if (sVerbose) Slog.v(TAG, "Sending refreshed SurfacePackage to IME");
+ try {
+ mInlineContentCallback.onContent(result, mActualWidth,
+ mActualHeight);
+ handleUpdateRefCount(1);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onContent");
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling getSurfacePackage.");
+ }
+ }
+ }
+
+ private void handleUpdateRefCount(int delta) {
+ cancelPendingReleaseViewRequest();
+ mRefCount += delta;
+ if (mRefCount <= 0) {
+ mDelayedReleaseViewRunnable = () -> {
+ if (mInlineSuggestionUi != null) {
+ try {
+ if (sVerbose) Slog.v(TAG, "releasing the host");
+ mInlineSuggestionUi.releaseSurfaceControlViewHost();
+ mInlineSuggestionUi = null;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling releaseSurfaceControlViewHost");
+ }
+ }
+ mDelayedReleaseViewRunnable = null;
+ };
+ mHandler.postDelayed(mDelayedReleaseViewRunnable, RELEASE_REMOTE_VIEW_HOST_DELAY_MS);
+ }
+ }
+
+ private void cancelPendingReleaseViewRequest() {
+ if (mDelayedReleaseViewRunnable != null) {
+ mHandler.removeCallbacks(mDelayedReleaseViewRunnable);
+ mDelayedReleaseViewRunnable = null;
+ }
+ }
+
+ /**
+ * This is called when a new inline suggestion UI is inflated from the ext services.
+ */
+ private void handleInlineSuggestionUiReady(IInlineSuggestionUi content,
+ SurfaceControlViewHost.SurfacePackage surfacePackage, int width, int height) {
+ mInlineSuggestionUi = content;
+ mRefCount = 0;
+ mWaitingForUiCreation = false;
+ mActualWidth = width;
+ mActualHeight = height;
+ if (mInlineContentCallback != null) {
+ try {
+ if (sVerbose) Slog.v(TAG, "Sending new UI content to IME");
+ handleUpdateRefCount(1);
+ mInlineContentCallback.onContent(surfacePackage, mActualWidth, mActualHeight);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onContent");
+ }
+ }
+ if (surfacePackage != null) {
+ surfacePackage.release();
+ }
+ }
+
+ private void handleOnClick() {
+ // Autofill the value
+ mRemoteInlineSuggestionViewConnector.onClick();
+
+ // Notify the remote process (IME) that hosts the embedded UI that it's clicked
+ if (mInlineContentCallback != null) {
+ try {
+ mInlineContentCallback.onClick();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onClick");
+ }
+ }
+ }
+
+ private void handleOnLongClick() {
+ // Notify the remote process (IME) that hosts the embedded UI that it's long clicked
+ if (mInlineContentCallback != null) {
+ try {
+ mInlineContentCallback.onLongClick();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onLongClick");
+ }
+ }
+ }
+
+ private void handleOnError() {
+ mRemoteInlineSuggestionViewConnector.onError();
+ }
+
+ private void handleOnTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
+ mRemoteInlineSuggestionViewConnector.onTransferTouchFocusToImeWindow(sourceInputToken,
+ displayId);
+ }
+
+ private void handleOnStartIntentSender(IntentSender intentSender) {
+ mRemoteInlineSuggestionViewConnector.onStartIntentSender(intentSender);
+ }
+
+ /**
+ * Responsible for communicating with the inline suggestion view owning process.
+ */
+ private class InlineSuggestionUiCallbackImpl extends IInlineSuggestionUiCallback.Stub {
+
+ @Override
+ public void onClick() {
+ mHandler.post(RemoteInlineSuggestionUi.this::handleOnClick);
+ }
+
+ @Override
+ public void onLongClick() {
+ mHandler.post(RemoteInlineSuggestionUi.this::handleOnLongClick);
+ }
+
+ @Override
+ public void onContent(IInlineSuggestionUi content,
+ SurfaceControlViewHost.SurfacePackage surface, int width, int height) {
+ mHandler.post(() -> handleInlineSuggestionUiReady(content, surface, width, height));
+ }
+
+ @Override
+ public void onError() {
+ mHandler.post(RemoteInlineSuggestionUi.this::handleOnError);
+ }
+
+ @Override
+ public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
+ mHandler.post(() -> handleOnTransferTouchFocusToImeWindow(sourceInputToken, displayId));
+ }
+
+ @Override
+ public void onStartIntentSender(IntentSender intentSender) {
+ mHandler.post(() -> handleOnStartIntentSender(intentSender));
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
new file mode 100644
index 0000000..9d23c17
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
@@ -0,0 +1,125 @@
+/*
+ * 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.autofill.ui;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentSender;
+import android.os.IBinder;
+import android.service.autofill.IInlineSuggestionUiCallback;
+import android.service.autofill.InlinePresentation;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.autofill.RemoteInlineSuggestionRenderService;
+import com.android.server.inputmethod.InputMethodManagerInternal;
+
+import java.util.function.Consumer;
+
+/**
+ * Wraps the parameters needed to create a new inline suggestion view in the remote renderer
+ * service, and handles the callback from the events on the created remote view.
+ */
+final class RemoteInlineSuggestionViewConnector {
+ private static final String TAG = RemoteInlineSuggestionViewConnector.class.getSimpleName();
+
+ @Nullable
+ private final RemoteInlineSuggestionRenderService mRemoteRenderService;
+ @NonNull
+ private final InlinePresentation mInlinePresentation;
+ @Nullable
+ private final IBinder mHostInputToken;
+ private final int mDisplayId;
+
+ @NonNull
+ private final Runnable mOnAutofillCallback;
+ @NonNull
+ private final Runnable mOnErrorCallback;
+ @NonNull
+ private final Consumer<IntentSender> mStartIntentSenderFromClientApp;
+
+ RemoteInlineSuggestionViewConnector(
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+ @NonNull InlinePresentation inlinePresentation,
+ @Nullable IBinder hostInputToken,
+ int displayId,
+ @NonNull Runnable onAutofillCallback,
+ @NonNull Runnable onErrorCallback,
+ @NonNull Consumer<IntentSender> startIntentSenderFromClientApp) {
+ mRemoteRenderService = remoteRenderService;
+ mInlinePresentation = inlinePresentation;
+ mHostInputToken = hostInputToken;
+ mDisplayId = displayId;
+
+ mOnAutofillCallback = onAutofillCallback;
+ mOnErrorCallback = onErrorCallback;
+ mStartIntentSenderFromClientApp = startIntentSenderFromClientApp;
+ }
+
+ /**
+ * Calls the remote renderer service to create a new inline suggestion view.
+ *
+ * @return true if the call is made to the remote renderer service, false otherwise.
+ */
+ public boolean renderSuggestion(int width, int height,
+ @NonNull IInlineSuggestionUiCallback callback) {
+ if (mRemoteRenderService != null) {
+ if (sDebug) Slog.d(TAG, "Request to recreate the UI");
+ mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
+ mHostInputToken, mDisplayId);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Handles the callback for the event of remote view being clicked.
+ */
+ public void onClick() {
+ mOnAutofillCallback.run();
+ }
+
+ /**
+ * Handles the callback for the remote error when creating or interacting with the view.
+ */
+ public void onError() {
+ mOnErrorCallback.run();
+ }
+
+ /**
+ * Handles the callback for transferring the touch event on the remote view to the IME
+ * process.
+ */
+ public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
+ final InputMethodManagerInternal inputMethodManagerInternal =
+ LocalServices.getService(InputMethodManagerInternal.class);
+ if (!inputMethodManagerInternal.transferTouchFocusToImeWindow(sourceInputToken,
+ displayId)) {
+ Slog.e(TAG, "Cannot transfer touch focus from suggestion to IME");
+ mOnErrorCallback.run();
+ }
+ }
+
+ /**
+ * Handles starting an intent sender from the client app's process.
+ */
+ public void onStartIntentSender(IntentSender intentSender) {
+ mStartIntentSenderFromClientApp.accept(intentSender);
+ }
+}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 21ac3cd..a95a0c2 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -97,7 +97,7 @@
"android.hardware.power-V1.0-java",
"android.hardware.tv.cec-V1.0-java",
"android.hardware.vibrator-java",
- "android.net.ipsec.ike.stubs.module_libs_api",
+ "android.net.ipsec.ike.stubs.module_lib",
"app-compat-annotations",
"framework-tethering-stubs-module_libs_api",
"service-permission-stubs",
@@ -130,6 +130,7 @@
"dnsresolver_aidl_interface-java",
"netd_aidl_interfaces-platform-java",
"overlayable_policy_aidl-java",
+ "SurfaceFlingerProperties",
],
}
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index f688759..fa84427 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -315,4 +315,15 @@
* @return {@code true} if the pruning was successful, {@code false} otherwise
*/
public abstract boolean pruneUninstalledPackagesData(@UserIdInt int userId);
+
+ /**
+ * Called by {@link com.android.server.usage.UsageStatsIdleService} between 24 to 48 hours of
+ * when the user is first unlocked to update the usage stats package mappings data that might
+ * be stale or have existed from a restore and belongs to packages that are not installed for
+ * this user anymore.
+ * Note: this is only executed for the system user.
+ *
+ * @return {@code true} if the updating was successful, {@code false} otherwise
+ */
+ public abstract boolean updatePackageMappingsData();
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2c63c6f..1197154 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2740,7 +2740,7 @@
// the Messenger, but if this ever changes, not making a defensive copy
// here will give attack vectors to clients using this code path.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork();
+ networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
}
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
@@ -3087,10 +3087,6 @@
@Override
public void notifyDataStallSuspected(DataStallReportParcelable p) {
- final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
- p.detectionMethod, mNetId, p.timestampMillis);
-
final PersistableBundle extras = new PersistableBundle();
switch (p.detectionMethod) {
case DETECTION_METHOD_DNS_EVENTS:
@@ -3105,12 +3101,9 @@
log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
return;
}
- msg.setData(new Bundle(extras));
- // NetworkStateTrackerHandler currently doesn't take any actions based on data
- // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
- // the cost of going through two handlers.
- mConnectivityDiagnosticsHandler.sendMessage(msg);
+ proxyDataStallToConnectivityDiagnosticsHandler(
+ p.detectionMethod, mNetId, p.timestampMillis, extras);
}
@Override
@@ -3124,6 +3117,19 @@
}
}
+ private void proxyDataStallToConnectivityDiagnosticsHandler(int detectionMethod, int netId,
+ long timestampMillis, @NonNull PersistableBundle extras) {
+ final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
+ detectionMethod, netId, timestampMillis);
+ msg.setData(new Bundle(extras));
+
+ // NetworkStateTrackerHandler currently doesn't take any actions based on data
+ // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
+ // the cost of going through two handlers.
+ mConnectivityDiagnosticsHandler.sendMessage(msg);
+ }
+
private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
return isPrivateDnsValidationRequired(nai.networkCapabilities);
}
@@ -5859,7 +5865,7 @@
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
// sees capabilities that may be malicious, which might prevent mistakes in the future.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork();
+ networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid());
} else {
enforceNetworkFactoryPermission();
}
@@ -5872,7 +5878,7 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId);
+ this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
@@ -5973,7 +5979,8 @@
// Start or stop DNS64 detection and 464xlat according to network state.
networkAgent.clatd.update();
notifyIfacesChangedForNetworkStats();
- networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
+ networkAgent.networkMonitor().notifyLinkPropertiesChanged(
+ new LinkProperties(newLp, true /* parcelSensitiveFields */));
if (networkAgent.everConnected) {
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -7153,7 +7160,9 @@
networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
networkAgent.networkMonitor().notifyNetworkConnected(
- networkAgent.linkProperties, networkAgent.networkCapabilities);
+ new LinkProperties(networkAgent.linkProperties,
+ true /* parcelSensitiveFields */),
+ networkAgent.networkCapabilities);
scheduleUnvalidatedPrompt(networkAgent);
// Whether a particular NetworkRequest listen should cause signal strength thresholds to
@@ -8151,4 +8160,24 @@
0,
callback));
}
+
+ @Override
+ public void simulateDataStall(int detectionMethod, long timestampMillis,
+ @NonNull Network network, @NonNull PersistableBundle extras) {
+ enforceAnyPermissionOf(android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ android.Manifest.permission.NETWORK_STACK);
+ final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
+ if (!nc.hasTransport(TRANSPORT_TEST)) {
+ throw new SecurityException("Data Stall simluation is only possible for test networks");
+ }
+
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null || nai.creatorUid != Binder.getCallingUid()) {
+ throw new SecurityException("Data Stall simulation is only possible for network "
+ + "creators");
+ }
+
+ proxyDataStallToConnectivityDiagnosticsHandler(
+ detectionMethod, network.netId, timestampMillis, extras);
+ }
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 905c489..6402e07 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1776,7 +1776,7 @@
socketRecord =
userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId());
}
- SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId());
+ SpiRecord spiRecord = transformInfo.getSpiRecord();
int mark =
(direction == IpSecManager.DIRECTION_OUT)
@@ -1809,7 +1809,7 @@
// Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys,
// but want to guarantee outbound packets are sent over the new SA.
- spi = transformInfo.getSpiRecord().getSpi();
+ spi = spiRecord.getSpi();
}
// Always update the policy with the relevant XFRM_IF_ID
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index bfcde97..829fca6 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -253,10 +253,7 @@
logCriticalInfo(Log.DEBUG,
"Finished rescue level " + levelToString(level));
} catch (Throwable t) {
- final String msg = ExceptionUtils.getCompleteMessage(t);
- EventLogTags.writeRescueFailure(level, msg);
- logCriticalInfo(Log.ERROR,
- "Failed rescue level " + levelToString(level) + ": " + msg);
+ logRescueException(level, t);
}
}
@@ -274,11 +271,31 @@
resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
break;
case LEVEL_FACTORY_RESET:
- RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+ // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
+ // when device shutting down.
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+ } catch (Throwable t) {
+ logRescueException(level, t);
+ }
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
break;
}
}
+ private static void logRescueException(int level, Throwable t) {
+ final String msg = ExceptionUtils.getCompleteMessage(t);
+ EventLogTags.writeRescueFailure(level, msg);
+ logCriticalInfo(Log.ERROR,
+ "Failed rescue level " + levelToString(level) + ": " + msg);
+ }
+
private static int mapRescueLevelToUserImpact(int rescueLevel) {
switch(rescueLevel) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index cfb79aa..b1b5ec0 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -169,7 +169,11 @@
@Override
public String toString() {
- return component.toShortString() + "@" + version + "[u" + userId + "]";
+ if (component == null) {
+ return "none";
+ } else {
+ return component.toShortString() + "@" + version + "[u" + userId + "]";
+ }
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 14fe0c5..e2a0c29 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -121,6 +121,7 @@
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.provider.DeviceConfig;
+import android.provider.DocumentsContract;
import android.provider.Downloads;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -432,6 +433,8 @@
private volatile int mDownloadsAuthorityAppId = -1;
+ private volatile int mExternalStorageAuthorityAppId = -1;
+
private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
private final Installer mInstaller;
@@ -1579,6 +1582,14 @@
writeSettingsLocked();
}
}
+
+ if (newState == VolumeInfo.STATE_MOUNTED) {
+ // Private volumes can be unmounted and re-mounted even after a user has
+ // been unlocked; on devices that support encryption keys tied to the filesystem,
+ // this requires setting up the keys again.
+ prepareUserStorageIfNeeded(vol);
+ }
+
// This is a blocking call to Storage Service which needs to process volume state changed
// before notifying other listeners.
// Intentionally called without the mLock to avoid deadlocking from the Storage Service.
@@ -1915,29 +1926,37 @@
mIAppOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
- ProviderInfo provider = mPmInternal.resolveContentProvider(
- MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.getUserId(UserHandle.USER_SYSTEM));
+ ProviderInfo provider = getProviderInfo(MediaStore.AUTHORITY);
if (provider != null) {
mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
sMediaStoreAuthorityProcessName = provider.applicationInfo.processName;
}
- provider = mPmInternal.resolveContentProvider(
- Downloads.Impl.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.getUserId(UserHandle.USER_SYSTEM));
-
+ provider = getProviderInfo(Downloads.Impl.AUTHORITY);
if (provider != null) {
mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
- try {
- mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
- mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
- } catch (RemoteException e) {
+ provider = getProviderInfo(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY);
+ if (provider != null) {
+ mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
+
+ if (!mIsFuseEnabled) {
+ try {
+ mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null,
+ mAppOpsCallback);
+ mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private ProviderInfo getProviderInfo(String authority) {
+ return mPmInternal.resolveContentProvider(
+ authority, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.getUserId(UserHandle.USER_SYSTEM));
}
private void updateLegacyStorageApps(String packageName, int uid, boolean hasLegacy) {
@@ -3266,10 +3285,38 @@
}
}
+ private void prepareUserStorageIfNeeded(VolumeInfo vol) {
+ if (vol.type != VolumeInfo.TYPE_PRIVATE) {
+ return;
+ }
+
+ final UserManager um = mContext.getSystemService(UserManager.class);
+ final UserManagerInternal umInternal =
+ LocalServices.getService(UserManagerInternal.class);
+
+ for (UserInfo user : um.getUsers(false /* includeDying */)) {
+ final int flags;
+ if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
+ flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
+ } else if (umInternal.isUserRunning(user.id)) {
+ flags = StorageManager.FLAG_STORAGE_DE;
+ } else {
+ continue;
+ }
+
+ prepareUserStorageInternal(vol.fsUuid, user.id, user.serialNumber, flags);
+ }
+ }
+
@Override
public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ prepareUserStorageInternal(volumeUuid, userId, serialNumber, flags);
+ }
+
+ private void prepareUserStorageInternal(String volumeUuid, int userId, int serialNumber,
+ int flags) {
try {
mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
// After preparing user storage, we should check if we should mount data mirror again,
@@ -4152,9 +4199,11 @@
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
- if (mIsFuseEnabled && mDownloadsAuthorityAppId == UserHandle.getAppId(uid)) {
+ if (mIsFuseEnabled && (mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
+ || mExternalStorageAuthorityAppId == UserHandle.getAppId(uid))) {
// DownloadManager can write in app-private directories on behalf of apps;
// give it write access to Android/
+ // ExternalStorageProvider can access Android/{data,obb} dirs in managed mode
return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
}
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 94d6b13..c061137 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -133,9 +133,11 @@
/**
* Shuts it down.
*
- * <p>Note:</p> should only be called by {@link SystemServer}.
+ * <p>Note:</p> should only be called *after* {@code PHASE_BOOT_COMPLETED} is sent to the
+ * {@link SystemService system services}.
*/
static void shutdown() {
+ Slog.d(TAG, "Shutdown requested");
synchronized (LOCK) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("WaitInitThreadPoolShutdown");
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index d2e12b5..197a2ce 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -222,6 +222,7 @@
if (phase == SystemService.PHASE_BOOT_COMPLETED) {
final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime;
t.logDuration("TotalBootTime", totalBootTime);
+ SystemServerInitThreadPool.shutdown();
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 97a5cfe..1d40e2e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -23,6 +23,7 @@
import static java.util.Arrays.copyOf;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -2459,7 +2460,7 @@
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE);
}
private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
@@ -2584,7 +2585,7 @@
intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY,
ApnSetting.getApnTypesStringFromBitmask(apnType));
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE);
}
private void enforceNotifyPermissionOrCarrierPrivilege(String method) {
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 0ea7346..d6bd5a1 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -317,39 +317,34 @@
"Cannot create network for non ipsec, non-testtun interface");
}
- // Setup needs to be done with NETWORK_STACK privileges.
- int callingUid = Binder.getCallingUid();
- Binder.withCleanCallingIdentity(
- () -> {
- try {
- mNMS.setInterfaceUp(iface);
+ try {
+ // This requires NETWORK_STACK privileges.
+ Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface));
- // Synchronize all accesses to mTestNetworkTracker to prevent the case
- // where:
- // 1. TestNetworkAgent successfully binds to death of binder
- // 2. Before it is added to the mTestNetworkTracker, binder dies,
- // binderDied() is called (on a different thread)
- // 3. This thread is pre-empted, put() is called after remove()
- synchronized (mTestNetworkTracker) {
- TestNetworkAgent agent =
- registerTestNetworkAgent(
- mHandler.getLooper(),
- mContext,
- iface,
- lp,
- isMetered,
- callingUid,
- administratorUids,
- binder);
+ // Synchronize all accesses to mTestNetworkTracker to prevent the case where:
+ // 1. TestNetworkAgent successfully binds to death of binder
+ // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called
+ // (on a different thread)
+ // 3. This thread is pre-empted, put() is called after remove()
+ synchronized (mTestNetworkTracker) {
+ TestNetworkAgent agent =
+ registerTestNetworkAgent(
+ mHandler.getLooper(),
+ mContext,
+ iface,
+ lp,
+ isMetered,
+ Binder.getCallingUid(),
+ administratorUids,
+ binder);
- mTestNetworkTracker.put(agent.getNetwork().netId, agent);
- }
- } catch (SocketException e) {
- throw new UncheckedIOException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- });
+ mTestNetworkTracker.put(agent.getNetwork().netId, agent);
+ }
+ } catch (SocketException e) {
+ throw new UncheckedIOException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** Teardown a test network */
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 70b6398..f42e32d 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -122,6 +122,7 @@
private boolean mVrHeadset;
private boolean mComputedNightMode;
private int mCarModeEnableFlags;
+ private boolean mSetupWizardComplete;
// flag set by resource, whether to enable Car dock launch when starting car mode.
private boolean mEnableCarDockLaunch = true;
@@ -163,6 +164,14 @@
mConfiguration.setToDefaults();
}
+ @VisibleForTesting
+ protected UiModeManagerService(Context context, boolean setupWizardComplete,
+ TwilightManager tm) {
+ this(context);
+ mSetupWizardComplete = setupWizardComplete;
+ mTwilightManager = tm;
+ }
+
private static Intent buildHomeIntent(String category) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(category);
@@ -276,6 +285,25 @@
}
};
+ private final ContentObserver mSetupWizardObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ synchronized (mLock) {
+ // setup wizard is done now so we can unblock
+ if (setupWizardCompleteForCurrentUser() && !selfChange) {
+ mSetupWizardComplete = true;
+ getContext().getContentResolver()
+ .unregisterContentObserver(mSetupWizardObserver);
+ // update night mode
+ Context context = getContext();
+ updateNightModeFromSettingsLocked(context, context.getResources(),
+ UserHandle.getCallingUserId());
+ updateLocked(0, 0);
+ }
+ }
+ }
+ };
+
private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange, Uri uri) {
@@ -293,6 +321,13 @@
}
@Override
+ public void onSwitchUser(int userHandle) {
+ super.onSwitchUser(userHandle);
+ getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
+ verifySetupWizardCompleted();
+ }
+
+ @Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
synchronized (mLock) {
@@ -304,7 +339,6 @@
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mLocalPowerManager =
LocalServices.getService(PowerManagerInternal.class);
- mTwilightManager = getLocalService(TwilightManager.class);
initPowerSave();
mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
registerVrStateListener();
@@ -330,8 +364,13 @@
@Override
public void onStart() {
final Context context = getContext();
+ // If setup isn't complete for this user listen for completion so we can unblock
+ // being able to send a night mode configuration change event
+ verifySetupWizardCompleted();
final Resources res = context.getResources();
+ mNightMode = res.getInteger(
+ com.android.internal.R.integer.config_defaultNightMode);
mDefaultUiModeType = res.getInteger(
com.android.internal.R.integer.config_defaultUiModeType);
mCarModeKeepsScreenOn = (res.getInteger(
@@ -342,7 +381,7 @@
com.android.internal.R.bool.config_enableCarDockHomeLaunch);
mUiModeLocked = res.getBoolean(com.android.internal.R.bool.config_lockUiMode);
mNightModeLocked = res.getBoolean(com.android.internal.R.bool.config_lockDayNightMode);
-
+ mTwilightManager = getLocalService(TwilightManager.class);
final PackageManager pm = context.getPackageManager();
mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
|| pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
@@ -404,6 +443,20 @@
return mConfiguration;
}
+ // Records whether setup wizard has happened or not and adds an observer for this user if not.
+ private void verifySetupWizardCompleted() {
+ final Context context = getContext();
+ final int userId = UserHandle.getCallingUserId();
+ if (!setupWizardCompleteForCurrentUser()) {
+ mSetupWizardComplete = false;
+ context.getContentResolver().registerContentObserver(
+ Secure.getUriFor(
+ Secure.USER_SETUP_COMPLETE), false, mSetupWizardObserver, userId);
+ } else {
+ mSetupWizardComplete = true;
+ }
+ }
+
private boolean setupWizardCompleteForCurrentUser() {
return Secure.getIntForUser(getContext().getContentResolver(),
Secure.USER_SETUP_COMPLETE, 0, UserHandle.getCallingUserId()) == 1;
@@ -429,27 +482,35 @@
* @return True if the new value is different from the old value. False otherwise.
*/
private boolean updateNightModeFromSettingsLocked(Context context, Resources res, int userId) {
- final int defaultNightMode = res.getInteger(
- com.android.internal.R.integer.config_defaultNightMode);
int oldNightMode = mNightMode;
- mNightMode = Secure.getIntForUser(context.getContentResolver(),
- Secure.UI_NIGHT_MODE, defaultNightMode, userId);
- mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
- Secure.UI_NIGHT_MODE_OVERRIDE_ON, 0, userId) != 0;
- mOverrideNightModeOff = Secure.getIntForUser(context.getContentResolver(),
- Secure.UI_NIGHT_MODE_OVERRIDE_OFF, 0, userId) != 0;
- mCustomAutoNightModeStartMilliseconds = LocalTime.ofNanoOfDay(
- Secure.getLongForUser(context.getContentResolver(),
- Secure.DARK_THEME_CUSTOM_START_TIME,
- DEFAULT_CUSTOM_NIGHT_START_TIME.toNanoOfDay() / 1000L, userId) * 1000);
- mCustomAutoNightModeEndMilliseconds = LocalTime.ofNanoOfDay(
- Secure.getLongForUser(context.getContentResolver(),
- Secure.DARK_THEME_CUSTOM_END_TIME,
- DEFAULT_CUSTOM_NIGHT_END_TIME.toNanoOfDay() / 1000L, userId) * 1000);
+ if (mSetupWizardComplete) {
+ mNightMode = Secure.getIntForUser(context.getContentResolver(),
+ Secure.UI_NIGHT_MODE, mNightMode, userId);
+ mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
+ Secure.UI_NIGHT_MODE_OVERRIDE_ON, 0, userId) != 0;
+ mOverrideNightModeOff = Secure.getIntForUser(context.getContentResolver(),
+ Secure.UI_NIGHT_MODE_OVERRIDE_OFF, 0, userId) != 0;
+ mCustomAutoNightModeStartMilliseconds = LocalTime.ofNanoOfDay(
+ Secure.getLongForUser(context.getContentResolver(),
+ Secure.DARK_THEME_CUSTOM_START_TIME,
+ DEFAULT_CUSTOM_NIGHT_START_TIME.toNanoOfDay() / 1000L, userId) * 1000);
+ mCustomAutoNightModeEndMilliseconds = LocalTime.ofNanoOfDay(
+ Secure.getLongForUser(context.getContentResolver(),
+ Secure.DARK_THEME_CUSTOM_END_TIME,
+ DEFAULT_CUSTOM_NIGHT_END_TIME.toNanoOfDay() / 1000L, userId) * 1000);
+ }
return oldNightMode != mNightMode;
}
+ private static long toMilliSeconds(LocalTime t) {
+ return t.toNanoOfDay() / 1000;
+ }
+
+ private static LocalTime fromMilliseconds(long t) {
+ return LocalTime.ofNanoOfDay(t * 1000);
+ }
+
private void registerScreenOffEventLocked() {
if (mPowerSave) return;
mWaitForScreenOff = true;
@@ -1385,8 +1446,11 @@
pw.println("UiModeManager service (uimode) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" night [yes|no|auto]");
+ pw.println(" night [yes|no|auto|custom]");
pw.println(" Set or read night mode.");
+ pw.println(" time [start|end] <ISO time>");
+ pw.println(" Set custom start/end schedule time"
+ + " (night mode must be set to custom to apply).");
}
@Override
@@ -1399,6 +1463,8 @@
switch (cmd) {
case "night":
return handleNightMode();
+ case "time":
+ return handleCustomTime();
default:
return handleDefaultCommands(cmd);
}
@@ -1409,6 +1475,34 @@
return -1;
}
+ private int handleCustomTime() throws RemoteException {
+ final String modeStr = getNextArg();
+ if (modeStr == null) {
+ printCustomTime();
+ return 0;
+ }
+ switch (modeStr) {
+ case "start":
+ final String start = getNextArg();
+ mInterface.setCustomNightModeStart(toMilliSeconds(LocalTime.parse(start)));
+ return 0;
+ case "end":
+ final String end = getNextArg();
+ mInterface.setCustomNightModeEnd(toMilliSeconds(LocalTime.parse(end)));
+ return 0;
+ default:
+ getErrPrintWriter().println("command must be in [start|end]");
+ return -1;
+ }
+ }
+
+ private void printCustomTime() throws RemoteException {
+ getOutPrintWriter().println("start " + fromMilliseconds(
+ mInterface.getCustomNightModeStart()).toString());
+ getOutPrintWriter().println("end " + fromMilliseconds(
+ mInterface.getCustomNightModeEnd()).toString());
+ }
+
private int handleNightMode() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
final String modeStr = getNextArg();
@@ -1424,7 +1518,8 @@
return 0;
} else {
err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
- + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO + "'");
+ + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO
+ + "', or '" + NIGHT_MODE_STR_CUSTOM + "'");
return -1;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8d35152..37f1ad1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2098,6 +2098,7 @@
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
+ ServiceManager.addService("cacheinfo", new CacheBinder(this));
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
@@ -2191,16 +2192,18 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ try {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(false);
+ }
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
- "meminfo", pw)) return;
- PriorityDump.dump(mPriorityDumper, fd, pw, args);
-
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "meminfo", pw)) return;
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
+ } finally {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(true);
+ }
}
}
}
@@ -2213,16 +2216,18 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ try {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(false);
+ }
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
- "gfxinfo", pw)) return;
- mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
-
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "gfxinfo", pw)) return;
+ mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
+ } finally {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(true);
+ }
}
}
}
@@ -2235,16 +2240,18 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ try {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(false);
+ }
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
- "dbinfo", pw)) return;
- mActivityManagerService.dumpDbInfo(fd, pw, args);
-
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "dbinfo", pw)) return;
+ mActivityManagerService.dumpDbInfo(fd, pw, args);
+ } finally {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(true);
+ }
}
}
}
@@ -2280,6 +2287,34 @@
}
}
+ static class CacheBinder extends Binder {
+ ActivityManagerService mActivityManagerService;
+
+ CacheBinder(ActivityManagerService activityManagerService) {
+ mActivityManagerService = activityManagerService;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ try {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(false);
+ }
+
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "cacheinfo", pw)) {
+ return;
+ }
+
+ mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
+ } finally {
+ if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
+ Process.enableFreezer(true);
+ }
+ }
+ }
+ }
+
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
private static ActivityTaskManagerService sAtm;
@@ -8766,27 +8801,6 @@
}
@Override
- public boolean isUidActiveOrForeground(int uid, String callingPackage) {
- if (!hasUsageStatsPermission(callingPackage)) {
- enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
- "isUidActiveOrForeground");
- }
- synchronized (this) {
- final boolean isActive = isUidActiveLocked(uid);
- if (isActive) {
- return true;
- }
- }
- final boolean isForeground = mAtmInternal.isUidForeground(uid);
- if (isForeground) {
- Slog.wtf(TAG, "isUidActiveOrForeground: isUidActive false but "
- + " isUidForeground true, uid:" + uid
- + " callingPackage:" + callingPackage);
- }
- return isForeground;
- }
-
- @Override
public void setPersistentVrThread(int tid) {
mActivityTaskManager.setPersistentVrThread(tid);
}
@@ -11104,18 +11118,22 @@
void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) {
pw.print(prefix);
- pw.print("#");
+ pw.print('#');
+ if (index < 10) {
+ pw.print(' ');
+ }
pw.print(index);
pw.print(": ");
pw.print(ProcessList.makeOomAdjString(proc.setAdj, false));
- pw.print(" ");
+ pw.print(' ');
pw.print(ProcessList.makeProcStateString(proc.getCurProcState()));
- pw.print(" ");
+ pw.print(' ');
+ ActivityManager.printCapabilitiesSummary(pw, proc.curCapability);
+ pw.print(' ');
pw.print(proc.toShortString());
- pw.print(" ");
if (proc.hasActivitiesOrRecentTasks() || proc.hasClientActivities()
|| proc.treatLikeActivity) {
- pw.print(" activity=");
+ pw.print(" act:");
boolean printed = false;
if (proc.hasActivities()) {
pw.print("activities");
@@ -12580,7 +12598,7 @@
char schedGroup;
switch (r.setSchedGroup) {
case ProcessList.SCHED_GROUP_BACKGROUND:
- schedGroup = 'B';
+ schedGroup = 'b';
break;
case ProcessList.SCHED_GROUP_DEFAULT:
schedGroup = 'F';
@@ -12591,6 +12609,9 @@
case ProcessList.SCHED_GROUP_RESTRICTED:
schedGroup = 'R';
break;
+ case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
+ schedGroup = 'B';
+ break;
default:
schedGroup = '?';
break;
@@ -12618,7 +12639,10 @@
pw.print(foreground);
pw.print('/');
pw.print(procState);
- pw.print(" trm:");
+ pw.print(' ');
+ ActivityManager.printCapabilitiesSummary(pw, r.curCapability);
+ pw.print(' ');
+ pw.print(" t:");
if (r.trimMemoryLevel < 10) pw.print(' ');
pw.print(r.trimMemoryLevel);
pw.print(' ');
@@ -12733,6 +12757,39 @@
}
}
+ final void dumpBinderCacheContents(FileDescriptor fd, PrintWriter pw, String[] args) {
+ ArrayList<ProcessRecord> procs = collectProcesses(pw, 0, false, args);
+ if (procs == null) {
+ pw.println("No process found for: " + args[0]);
+ return;
+ }
+
+ pw.println("Per-process Binder Cache Contents");
+
+ for (int i = procs.size() - 1; i >= 0; i--) {
+ ProcessRecord r = procs.get(i);
+ if (r.thread != null) {
+ pw.println("\n\n** Cache info for pid " + r.pid + " [" + r.processName + "] **");
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.thread.dumpCacheInfo(tp.getWriteFd(), args);
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println("Failure while dumping the app " + r);
+ pw.flush();
+ } catch (RemoteException e) {
+ pw.println("Got a RemoteException while dumping the app " + r);
+ pw.flush();
+ }
+ }
+ }
+ }
+
final void dumpDbInfo(FileDescriptor fd, PrintWriter pw, String[] args) {
ArrayList<ProcessRecord> procs = collectProcesses(pw, 0, false, args);
if (procs == null) {
@@ -13618,7 +13675,9 @@
pw.print(" unmapped + ");
pw.print(stringifyKBSize(ionPool));
pw.println(" pools)");
- kernelUsed += ionUnmapped;
+ // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
+ // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
+ kernelUsed += ionHeap;
}
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
@@ -14424,7 +14483,9 @@
memInfoBuilder.append(" ION: ");
memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
memInfoBuilder.append("\n");
- kernelUsed += ionUnmapped;
+ // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
+ // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
+ kernelUsed += ionHeap;
}
memInfoBuilder.append(" Used RAM: ");
memInfoBuilder.append(stringifyKBSize(
@@ -20201,4 +20262,15 @@
mUsageStatsService.reportLocusUpdate(activity, userId, locusId, appToken);
}
}
+
+ @Override
+ public boolean isAppFreezerSupported() {
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ return mOomAdjuster.mCachedAppOptimizer.isFreezerSupported();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 86d9028..f9d204f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -33,6 +33,7 @@
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
@@ -407,7 +408,7 @@
/**
* Determines whether the freezer is correctly supported by this system
*/
- public boolean isFreezerSupported() {
+ public static boolean isFreezerSupported() {
boolean supported = false;
FileReader fr = null;
@@ -443,7 +444,13 @@
*/
@GuardedBy("mPhenotypeFlagLock")
private void updateUseFreezer() {
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ final String configOverride = Settings.Global.getString(mAm.mContext.getContentResolver(),
+ Settings.Global.CACHED_APPS_FREEZER_ENABLED);
+
+ if ("disabled".equals(configOverride)) {
+ mUseFreezer = false;
+ } else if ("enabled".equals(configOverride)
+ || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
mUseFreezer = isFreezerSupported();
}
diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
deleted file mode 100644
index 0e34801..0000000
--- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.am;
-
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowInsets;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.R;
-
-
-/**
- * Dialog to show when a user switch it about to happen for the car. The intent is to snapshot the
- * screen immediately after the dialog shows so that the user is informed that something is
- * happening in the background rather than just freeze the screen and not know if the user-switch
- * affordance was being handled.
- */
-final class CarUserSwitchingDialog extends UserSwitchingDialog {
-
- private static final String TAG = "ActivityManagerCarUserSwitchingDialog";
- private View mView;
-
- public CarUserSwitchingDialog(ActivityManagerService service, Context context, UserInfo oldUser,
- UserInfo newUser, boolean aboveSystem, String switchingFromSystemUserMessage,
- String switchingToSystemUserMessage) {
- super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
- }
-
- @Override
- void inflateContent() {
- // Set up the dialog contents
- setCancelable(false);
- Resources res = getContext().getResources();
- // Custom view due to alignment and font size requirements
- getContext().setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog);
- mView = LayoutInflater.from(getContext()).inflate(
- R.layout.car_user_switching_dialog,
- null);
-
- UserManager userManager =
- (UserManager) getContext().getSystemService(Context.USER_SERVICE);
- Bitmap bitmap = userManager.getUserIcon(mNewUser.id);
- if (bitmap != null) {
- CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(bitmap,
- res.getDimension(R.dimen.car_fullscreen_user_pod_image_avatar_height));
- ((ImageView) mView.findViewById(R.id.user_loading_avatar))
- .setImageDrawable(drawable);
- }
-
- TextView msgView = mView.findViewById(R.id.user_loading);
-
- // TODO(b/145132885): use constant from CarSettings
- boolean showInfo = "true".equals(Settings.Global.getString(
- getContext().getContentResolver(),
- "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE"));
-
- if (showInfo) {
- msgView.setText(res.getString(R.string.car_loading_profile) + " user\n(from "
- + mOldUser.id + " to " + mNewUser.id + ")");
- } else {
- msgView.setText(res.getString(R.string.car_loading_profile));
- }
- setView(mView);
- }
-
- @Override
- public void show() {
- super.show();
- hideNavigationBar();
- }
-
- private void hideNavigationBar() {
- mView.getWindowInsetsController().hide(WindowInsets.Type.navigationBars());
- }
-
- /**
- * Converts the user icon to a circularly clipped one. This is used in the User Picker and
- * Settings.
- */
- static class CircleFramedDrawable extends Drawable {
-
- private final Bitmap mBitmap;
- private final int mSize;
- private final Paint mPaint;
-
- private float mScale;
- private Rect mSrcRect;
- private RectF mDstRect;
-
- public static CircleFramedDrawable getInstance(Bitmap icon, float iconSize) {
- CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize);
- return instance;
- }
-
- public CircleFramedDrawable(Bitmap icon, int size) {
- super();
- mSize = size;
-
- mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(mBitmap);
-
- final int width = icon.getWidth();
- final int height = icon.getHeight();
- final int square = Math.min(width, height);
-
- final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2,
- square, square);
- final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
-
- final Path fillPath = new Path();
- fillPath.addArc(circleRect, 0f, 360f);
-
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
-
- // opaque circle
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setColor(Color.BLACK);
- mPaint.setStyle(Paint.Style.FILL);
- canvas.drawPath(fillPath, mPaint);
-
- // mask in the icon where the bitmap is opaque
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
-
- // prepare paint for frame drawing
- mPaint.setXfermode(null);
-
- mScale = 1f;
-
- mSrcRect = new Rect(0, 0, mSize, mSize);
- mDstRect = new RectF(0, 0, mSize, mSize);
- }
-
- @Override
- public void draw(Canvas canvas) {
- final float inside = mScale * mSize;
- final float pad = (mSize - inside) / 2f;
-
- mDstRect.set(pad, pad, mSize - pad, mSize - pad);
- canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void setAlpha(int alpha) {
- // Needed to implement abstract method. Do nothing.
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- // Needed to implement abstract method. Do nothing.
- }
- }
-}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 17f4187..b818ccf 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -95,14 +95,15 @@
30069 am_unfreeze (Pid|1|5),(Process Name|3)
# User switch events
-30070 uc_finish_user_unlocking (UID|1|5)
-30071 uc_finish_user_unlocked (UID|1|5)
-30072 uc_finish_user_unlocked_completed (UID|1|5)
-30073 uc_finish_user_stopping (UID|1|5)
-30074 uc_finish_user_stopped (UID|1|5)
-30075 uc_switch_user (UID|1|5)
-30076 uc_start_user_internal (UID|1|5)
-30077 uc_unlock_user (UID|1|5)
-30078 uc_finish_user_boot (UID|1|5)
-30079 uc_dispatch_user_switch (oldUID|1|5) (newUID|1|5)
-30080 uc_continue_user_switch (oldUID|1|5) (newUID|1|5)
+30070 uc_finish_user_unlocking (userId|1|5)
+30071 uc_finish_user_unlocked (userId|1|5)
+30072 uc_finish_user_unlocked_completed (userId|1|5)
+30073 uc_finish_user_stopping (userId|1|5)
+30074 uc_finish_user_stopped (userId|1|5)
+30075 uc_switch_user (userId|1|5)
+30076 uc_start_user_internal (userId|1|5)
+30077 uc_unlock_user (userId|1|5)
+30078 uc_finish_user_boot (userId|1|5)
+30079 uc_dispatch_user_switch (oldUserId|1|5) (newUserId|1|5)
+30080 uc_continue_user_switch (oldUserId|1|5) (newUserId|1|5)
+30081 uc_send_user_broadcast (userId|1|5),(IntentAction|3)
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ad85853..c13bb5a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -151,15 +151,6 @@
@EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
static final long CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID = 136219221L;
- // TODO: remove this when development is done.
- // These are debug flags used between OomAdjuster and AppOpsService to detect and report absence
- // of the real flags.
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q = 1 << 27;
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q = 1 << 28;
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29;
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30;
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
-
/**
* For some direct access we need to power manager.
*/
@@ -1506,8 +1497,9 @@
//lost the capability, use temp location capability to mark this case.
//TODO: remove this block when development is done.
capabilityFromFGS |=
- (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
- != 0 ? DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
+ (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0
+ ? ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION
+ : 0;
}
if (s.mAllowWhileInUsePermissionInFgs) {
boolean enabled = false;
@@ -1520,22 +1512,22 @@
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
- : DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+ : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
- : DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
} else {
// Remove fgsType check and assign PROCESS_CAPABILITY_FOREGROUND_CAMERA
// and MICROPHONE when finish debugging.
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
- : DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
+ : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
- : DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
+ : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b753de9..108fb7d 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -972,7 +972,7 @@
return buildOomTag("vis", "vis", " ", setAdj,
ProcessList.VISIBLE_APP_ADJ, compact);
} else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- return buildOomTag("fore ", "fore", null, setAdj,
+ return buildOomTag("fg ", "fg ", " ", setAdj,
ProcessList.FOREGROUND_APP_ADJ, compact);
} else if (setAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
return buildOomTag("psvc ", "psvc", null, setAdj,
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index fc6931d..c5152c0 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -431,16 +431,46 @@
pw.print(" nextPssTime=");
TimeUtils.formatDuration(nextPssTime, nowUptime, pw);
pw.println();
- pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
- pw.print(" lruSeq="); pw.print(lruSeq);
- pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
- pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss*1024);
- pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
- pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw, lastCachedSwapPss*1024);
- pw.print(" lastRss="); DebugUtils.printSizeValue(pw, mLastRss * 1024);
+ pw.print(prefix); pw.print("lastPss="); DebugUtils.printSizeValue(pw, lastPss * 1024);
+ pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss * 1024);
+ pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss * 1024);
+ pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw,
+ lastCachedSwapPss * 1024);
+ pw.print(" lastRss="); DebugUtils.printSizeValue(pw, mLastRss * 1024);
pw.println();
pw.print(prefix); pw.print("procStateMemTracker: ");
procStateMemTracker.dumpLine(pw);
+ pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
+ pw.print(" lruSeq="); pw.println(lruSeq);
+ pw.print(prefix); pw.print("oom adj: max="); pw.print(maxAdj);
+ pw.print(" curRaw="); pw.print(mCurRawAdj);
+ pw.print(" setRaw="); pw.print(setRawAdj);
+ pw.print(" cur="); pw.print(curAdj);
+ pw.print(" set="); pw.println(setAdj);
+ pw.print(prefix); pw.print("lastCompactTime="); pw.print(lastCompactTime);
+ pw.print(" lastCompactAction="); pw.println(lastCompactAction);
+ pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup);
+ pw.print(" setSchedGroup="); pw.print(setSchedGroup);
+ pw.print(" systemNoUi="); pw.print(systemNoUi);
+ pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
+ pw.print(prefix); pw.print("curProcState="); pw.print(getCurProcState());
+ pw.print(" mRepProcState="); pw.print(mRepProcState);
+ pw.print(" pssProcState="); pw.print(pssProcState);
+ pw.print(" setProcState="); pw.print(setProcState);
+ pw.print(" lastStateTime=");
+ TimeUtils.formatDuration(lastStateTime, nowUptime, pw);
+ pw.println();
+ pw.print(prefix); pw.print("curCapability=");
+ ActivityManager.printCapabilitiesFull(pw, curCapability);
+ pw.print(" setCapability=");
+ ActivityManager.printCapabilitiesFull(pw, setCapability);
+ pw.println();
+ if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
+ pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
+ pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
+ pw.print(" hasAboveClient="); pw.print(hasAboveClient);
+ pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
+ }
pw.print(prefix); pw.print("cached="); pw.print(mCached);
pw.print(" empty="); pw.println(empty);
if (serviceb) {
@@ -451,32 +481,6 @@
pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
pw.print(" initialIdlePss="); pw.println(initialIdlePss);
}
- pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
- pw.print(" curRaw="); pw.print(mCurRawAdj);
- pw.print(" setRaw="); pw.print(setRawAdj);
- pw.print(" cur="); pw.print(curAdj);
- pw.print(" set="); pw.println(setAdj);
- pw.print(prefix); pw.print("lastCompactTime="); pw.print(lastCompactTime);
- pw.print(" lastCompactAction="); pw.print(lastCompactAction);
- pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup);
- pw.print(" setSchedGroup="); pw.print(setSchedGroup);
- pw.print(" systemNoUi="); pw.print(systemNoUi);
- pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- pw.print(prefix); pw.print("curProcState="); pw.print(getCurProcState());
- pw.print(" mRepProcState="); pw.print(mRepProcState);
- pw.print(" pssProcState="); pw.print(pssProcState);
- pw.print(" setProcState="); pw.print(setProcState);
- pw.print(" curCapability="); pw.print(curCapability);
- pw.print(" setCapability="); pw.print(setCapability);
- pw.print(" lastStateTime=");
- TimeUtils.formatDuration(lastStateTime, nowUptime, pw);
- pw.println();
- if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
- pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
- pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
- pw.print(" hasAboveClient="); pw.print(hasAboveClient);
- pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
- }
if (connectionService != null || connectionGroup != 0) {
pw.print(prefix); pw.print("connectionGroup="); pw.print(connectionGroup);
pw.print(" Importance="); pw.print(connectionImportance);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c7c2510..fac4a1e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -668,6 +668,8 @@
// Spin up app widgets prior to boot-complete, so they can be ready promptly
mInjector.startUserWidgets(userId);
+ mHandler.obtainMessage(USER_UNLOCKED_MSG, userId, 0).sendToTarget();
+
Slog.i(TAG, "Posting BOOT_COMPLETED user #" + userId);
// Do not report secondary users, runtime restarts or first boot/upgrade
if (userId == UserHandle.USER_SYSTEM
@@ -677,9 +679,6 @@
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__FRAMEWORK_BOOT_COMPLETED,
elapsedTimeMs);
}
-
- mHandler.obtainMessage(USER_UNLOCKED_MSG, userId, 0).sendToTarget();
-
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -2423,8 +2422,10 @@
logUserJourneyInfo(null, getUserInfo(msg.arg1), USER_JOURNEY_USER_START);
logUserLifecycleEvent(msg.arg1, USER_JOURNEY_USER_START,
USER_LIFECYCLE_EVENT_START_USER, true);
+
mInjector.getSystemServiceManager().startUser(TimingsTraceAndSlog.newAsyncLog(),
msg.arg1);
+
logUserLifecycleEvent(msg.arg1, USER_JOURNEY_USER_START,
USER_LIFECYCLE_EVENT_START_USER, false);
clearSessionId(msg.arg1, USER_JOURNEY_USER_START);
@@ -2456,6 +2457,7 @@
break;
case REPORT_USER_SWITCH_COMPLETE_MSG:
dispatchUserSwitchComplete(msg.arg1);
+
final int currentJourney = mUserSwitchUiEnabled ? USER_JOURNEY_USER_SWITCH_UI
: USER_JOURNEY_USER_SWITCH_FG;
logUserLifecycleEvent(msg.arg1, currentJourney,
@@ -2601,6 +2603,13 @@
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
int realCallingPid, @UserIdInt int userId) {
+
+ int logUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (logUserId == UserHandle.USER_NULL) {
+ logUserId = userId;
+ }
+ EventLog.writeEvent(EventLogTags.UC_SEND_USER_BROADCAST, logUserId, intent.getAction());
+
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
@@ -2666,6 +2675,8 @@
}
void sendPreBootBroadcast(@UserIdInt int userId, boolean quiet, final Runnable onFinish) {
+ EventLog.writeEvent(EventLogTags.UC_SEND_USER_BROADCAST,
+ userId, Intent.ACTION_PRE_BOOT_COMPLETED);
new PreBootBroadcaster(mService, userId, null, quiet) {
@Override
public void onFinished() {
@@ -2725,19 +2736,13 @@
void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
String switchingFromSystemUserMessage, String switchingToSystemUserMessage) {
- Dialog d;
if (!mService.mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- d = new UserSwitchingDialog(mService, mService.mContext, fromUser, toUser,
- true /* above system */, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
- } else {
- d = new CarUserSwitchingDialog(mService, mService.mContext, fromUser, toUser,
- true /* above system */, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
+ final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser,
+ toUser, true /* above system */, switchingFromSystemUserMessage,
+ switchingToSystemUserMessage);
+ d.show();
}
-
- d.show();
}
void reportGlobalUsageEventLocked(int event) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 63e01e0..ae38e81 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -66,11 +66,11 @@
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
-import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
-import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
-import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
+import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
+import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
import static java.lang.Long.max;
@@ -2582,6 +2582,28 @@
}
}
+ private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
+ int op, int uid, String packageName) {
+ boolean duplicate = false;
+ if (reports == null) {
+ reports = new ArrayList<>();
+ } else {
+ final int reportCount = reports.size();
+ for (int j = 0; j < reportCount; j++) {
+ ChangeRec report = reports.get(j);
+ if (report.op == op && report.pkg.equals(packageName)) {
+ duplicate = true;
+ break;
+ }
+ }
+ }
+ if (!duplicate) {
+ reports.add(new ChangeRec(op, uid, packageName));
+ }
+
+ return reports;
+ }
+
private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
@@ -2595,22 +2617,9 @@
for (int i=0; i<N; i++) {
ModeCallback cb = cbs.valueAt(i);
ArrayList<ChangeRec> reports = callbacks.get(cb);
- boolean duplicate = false;
- if (reports == null) {
- reports = new ArrayList<>();
- callbacks.put(cb, reports);
- } else {
- final int reportCount = reports.size();
- for (int j = 0; j < reportCount; j++) {
- ChangeRec report = reports.get(j);
- if (report.op == op && report.pkg.equals(packageName)) {
- duplicate = true;
- break;
- }
- }
- }
- if (!duplicate) {
- reports.add(new ChangeRec(op, uid, packageName));
+ ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName);
+ if (changed != reports) {
+ callbacks.put(cb, changed);
}
}
return callbacks;
@@ -2648,6 +2657,7 @@
enforceManageAppOpsModes(callingPid, callingUid, reqUid);
HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
+ ArrayList<ChangeRec> allChanges = new ArrayList<>();
synchronized (this) {
boolean changed = false;
for (int i = mUidStates.size() - 1; i >= 0; i--) {
@@ -2668,6 +2678,9 @@
mOpModeWatchers.get(code));
callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
mPackageModeWatchers.get(packageName));
+
+ allChanges = addChange(allChanges, code, uidState.uid,
+ packageName);
}
}
}
@@ -2707,6 +2720,7 @@
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
mPackageModeWatchers.get(packageName));
+ allChanges = addChange(allChanges, curOp.op, uid, packageName);
curOp.removeAttributionsWithNoTime();
if (curOp.mAttributions.isEmpty()) {
pkgOps.removeAt(j);
@@ -2741,6 +2755,15 @@
}
}
}
+
+ if (allChanges != null) {
+ int numChanges = allChanges.size();
+ for (int i = 0; i < numChanges; i++) {
+ ChangeRec change = allChanges.get(i);
+ notifyOpChangedSync(change.op, change.uid, change.pkg,
+ AppOpsManager.opToDefaultMode(change.op));
+ }
+ }
}
private void evalAllForegroundOpsLocked() {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 604b9f1..9cd9039 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -37,7 +37,12 @@
]
},
{
- "name": "CtsAppTestCases:ActivityManagerApi29Test"
+ "name": "CtsAppTestCases",
+ "options": [
+ {
+ "include-filter": "android.app.cts.ActivityManagerApi29Test"
+ }
+ ]
},
{
"name": "UidAtomTests:testAppOps"
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 40b6f42..df4c269 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -36,6 +36,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.PrintWriterPrinter;
@@ -43,6 +44,9 @@
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
/** @hide */
/*package*/ final class AudioDeviceBroker {
@@ -91,6 +95,9 @@
// TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
/*package*/ final Object mSetModeLock = new Object();
+ /** PID of current audio mode owner communicated by AudioService */
+ private int mModeOwnerPid = 0;
+
//-------------------------------------------------------------------
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
mContext = context;
@@ -136,6 +143,7 @@
/*package*/ void onSystemReady() {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
+ mModeOwnerPid = mAudioService.getModeOwnerPid();
mBtHelper.onSystemReady();
}
}
@@ -202,24 +210,57 @@
* @param eventSource for logging purposes
* @return true if speakerphone state changed
*/
- /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) {
+ /*package*/ boolean setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) {
synchronized (mDeviceStateLock) {
- final boolean wasOn = isSpeakerphoneOn();
- if (on) {
- if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
- setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
- }
- mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
- } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
- mForcedUseForComm = AudioSystem.FORCE_NONE;
+ if (!addSpeakerphoneClient(cb, pid, on)) {
+ return false;
}
-
- mForcedUseForCommExt = mForcedUseForComm;
- setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ final boolean wasOn = isSpeakerphoneOn();
+ updateSpeakerphoneOn(eventSource);
return (wasOn != isSpeakerphoneOn());
}
}
+ @GuardedBy("mDeviceStateLock")
+ private void updateSpeakerphoneOn(String eventSource) {
+ if (isSpeakerphoneOnRequested()) {
+ if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+ setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
+ }
+ mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+ } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
+ if (mBtHelper.isBluetoothScoOn()) {
+ mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+ setForceUse_Async(
+ AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
+ } else {
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+ mForcedUseForCommExt = mForcedUseForComm;
+ setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ }
+
+ /**
+ * Returns if speakerphone is requested ON or OFF.
+ * If the current audio mode owner is in the speakerphone client list, use this preference.
+ * Otherwise use first client's preference (first client corresponds to latest request).
+ * Speakerphone is requested OFF if no client is in the list.
+ * @return true if speakerphone is requested ON, false otherwise
+ */
+ @GuardedBy("mDeviceStateLock")
+ private boolean isSpeakerphoneOnRequested() {
+ if (mSpeakerphoneClients.isEmpty()) {
+ return false;
+ }
+ for (SpeakerphoneClient cl : mSpeakerphoneClients) {
+ if (cl.getPid() == mModeOwnerPid) {
+ return cl.isOn();
+ }
+ }
+ return mSpeakerphoneClients.get(0).isOn();
+ }
+
/*package*/ boolean isSpeakerphoneOn() {
synchronized (mDeviceStateLock) {
return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
@@ -280,6 +321,13 @@
final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
suppressNoisyIntent, a2dpVolume);
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
+ .set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED
+ ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
+ .set(MediaMetrics.Property.INDEX, a2dpVolume)
+ .record();
+
// operations of removing and posting messages related to A2DP device state change must be
// mutually exclusive
synchronized (mDeviceStateLock) {
@@ -371,7 +419,8 @@
}
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
- mForcedUseForComm = AudioSystem.FORCE_NONE;
+ mForcedUseForComm = isSpeakerphoneOnRequested()
+ ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
}
mForcedUseForCommExt = mForcedUseForComm;
AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
@@ -416,8 +465,8 @@
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
}
- /*package*/ void postDisconnectBluetoothSco(int exceptPid) {
- sendIMsgNoDelay(MSG_I_DISCONNECT_BT_SCO, SENDMSG_REPLACE, exceptPid);
+ /*package*/ void postSetModeOwnerPid(int pid) {
+ sendIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid);
}
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -470,7 +519,7 @@
}
/*package*/ int getModeOwnerPid() {
- return mAudioService.getModeOwnerPid();
+ return mModeOwnerPid;
}
/*package*/ int getDeviceForStream(int streamType) {
@@ -592,6 +641,10 @@
sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
}
+ /*package*/ void postSpeakerphoneClientDied(Object obj) {
+ sendLMsgNoDelay(MSG_L_SPEAKERPHONE_CLIENT_DIED, SENDMSG_QUEUE, obj);
+ }
+
/*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy,
AudioDeviceAttributes device)
{
@@ -661,7 +714,7 @@
new BtHelper.BluetoothA2dpDeviceInfo(btDevice);
return (mBrokerHandler.hasEqualMessages(
MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck)
- || mBrokerHandler.hasEqualMessages(
+ || mBrokerHandler.hasEqualMessages(
MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck));
}
@@ -694,7 +747,20 @@
} else {
pw.println("Message handler is null");
}
+
mDeviceInventory.dump(pw, prefix);
+
+ pw.println("\n" + prefix + "mForcedUseForComm: "
+ + AudioSystem.forceUseConfigToString(mForcedUseForComm));
+ pw.println(prefix + "mForcedUseForCommExt: "
+ + AudioSystem.forceUseConfigToString(mForcedUseForCommExt));
+ pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid);
+ pw.println(prefix + "Speakerphone clients:");
+ mSpeakerphoneClients.forEach((cl) -> {
+ pw.println(" " + prefix + "pid: " + cl.getPid() + " on: "
+ + cl.isOn() + " cb: " + cl.getBinder()); });
+
+ mBtHelper.dump(pw, prefix);
}
//---------------------------------------------------------------------
@@ -864,10 +930,16 @@
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
}
break;
- case MSG_I_DISCONNECT_BT_SCO:
+ case MSG_I_SET_MODE_OWNER_PID:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- mBtHelper.disconnectBluetoothSco(msg.arg1);
+ if (mModeOwnerPid != msg.arg1) {
+ mModeOwnerPid = msg.arg1;
+ updateSpeakerphoneOn("setNewModeOwner");
+ if (mModeOwnerPid != 0) {
+ mBtHelper.disconnectBluetoothSco(mModeOwnerPid);
+ }
+ }
}
}
break;
@@ -878,6 +950,11 @@
}
}
break;
+ case MSG_L_SPEAKERPHONE_CLIENT_DIED:
+ synchronized (mDeviceStateLock) {
+ speakerphoneClientDied(msg.obj);
+ }
+ break;
case MSG_TOGGLE_HDMI:
synchronized (mDeviceStateLock) {
mDeviceInventory.onToggleHdmi();
@@ -1008,7 +1085,7 @@
private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
- private static final int MSG_I_DISCONNECT_BT_SCO = 16;
+ private static final int MSG_I_SET_MODE_OWNER_PID = 16;
// process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo
private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
@@ -1038,6 +1115,8 @@
private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33;
private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
+ private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35;
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -1153,4 +1232,93 @@
time);
}
}
+
+ private class SpeakerphoneClient implements IBinder.DeathRecipient {
+ private final IBinder mCb;
+ private final int mPid;
+ private final boolean mOn;
+ SpeakerphoneClient(IBinder cb, int pid, boolean on) {
+ mCb = cb;
+ mPid = pid;
+ mOn = on;
+ }
+
+ public boolean registerDeathRecipient() {
+ boolean status = false;
+ try {
+ mCb.linkToDeath(this, 0);
+ status = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "SpeakerphoneClient could not link to " + mCb + " binder death");
+ }
+ return status;
+ }
+
+ public void unregisterDeathRecipient() {
+ try {
+ mCb.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "SpeakerphoneClient could not not unregistered to binder");
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ postSpeakerphoneClientDied(this);
+ }
+
+ IBinder getBinder() {
+ return mCb;
+ }
+
+ int getPid() {
+ return mPid;
+ }
+
+ boolean isOn() {
+ return mOn;
+ }
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ private void speakerphoneClientDied(Object obj) {
+ if (obj == null) {
+ return;
+ }
+ Log.w(TAG, "Speaker client died");
+ if (removeSpeakerphoneClient(((SpeakerphoneClient) obj).getBinder(), false) != null) {
+ updateSpeakerphoneOn("speakerphoneClientDied");
+ }
+ }
+
+ private SpeakerphoneClient removeSpeakerphoneClient(IBinder cb, boolean unregister) {
+ for (SpeakerphoneClient cl : mSpeakerphoneClients) {
+ if (cl.getBinder() == cb) {
+ if (unregister) {
+ cl.unregisterDeathRecipient();
+ }
+ mSpeakerphoneClients.remove(cl);
+ return cl;
+ }
+ }
+ return null;
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ private boolean addSpeakerphoneClient(IBinder cb, int pid, boolean on) {
+ // always insert new request at first position
+ removeSpeakerphoneClient(cb, true);
+ SpeakerphoneClient client = new SpeakerphoneClient(cb, pid, on);
+ if (client.registerDeathRecipient()) {
+ mSpeakerphoneClients.add(0, client);
+ return true;
+ }
+ return false;
+ }
+
+ // List of clients requesting speakerPhone ON
+ @GuardedBy("mDeviceStateLock")
+ private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
+ new ArrayList<SpeakerphoneClient>();
+
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7cac376..98d662a 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -52,7 +52,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
@@ -570,6 +569,10 @@
private int[] mAccessibilityServiceUids;
private final Object mAccessibilityServiceUidsLock = new Object();
+ // Uid of the active input method service to check if caller is the one or not.
+ private int mInputMethodServiceUid = android.os.Process.INVALID_UID;
+ private final Object mInputMethodServiceUidLock = new Object();
+
private int mEncodedSurroundMode;
private String mEnabledSurroundFormats;
private boolean mSurroundModeChanged;
@@ -1078,12 +1081,14 @@
sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
sendEnabledSurroundFormats(mContentResolver, true);
updateAssistantUId(true);
- updateCurrentImeUid(true);
AudioSystem.setRttEnabled(mRttEnabled);
}
synchronized (mAccessibilityServiceUidsLock) {
AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
}
+ synchronized (mInputMethodServiceUidLock) {
+ mAudioSystem.setCurrentImeUid(mInputMethodServiceUid);
+ }
synchronized (mHdmiClientLock) {
if (mHdmiManager != null && mHdmiTvClient != null) {
setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
@@ -1217,6 +1222,8 @@
*/
@NonNull
public List<AudioProductStrategy> getAudioProductStrategies() {
+ // verify permissions
+ enforceModifyAudioRoutingPermission();
return AudioProductStrategy.getAudioProductStrategies();
}
@@ -1226,6 +1233,8 @@
*/
@NonNull
public List<AudioVolumeGroup> getAudioVolumeGroups() {
+ // verify permissions
+ enforceModifyAudioRoutingPermission();
return AudioVolumeGroup.getAudioVolumeGroups();
}
@@ -1625,37 +1634,6 @@
}
}
- @GuardedBy("mSettingsLock")
- private void updateCurrentImeUid(boolean forceUpdate) {
- String imeId = Settings.Secure.getStringForUser(
- mContentResolver,
- Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.USER_CURRENT);
- if (TextUtils.isEmpty(imeId)) {
- Log.e(TAG, "updateCurrentImeUid() could not find current IME");
- return;
- }
- ComponentName componentName = ComponentName.unflattenFromString(imeId);
- if (componentName == null) {
- Log.e(TAG, "updateCurrentImeUid() got invalid service name for "
- + Settings.Secure.DEFAULT_INPUT_METHOD + ": " + imeId);
- return;
- }
- String packageName = componentName.getPackageName();
- int currentUserId = LocalServices.getService(ActivityManagerInternal.class)
- .getCurrentUserId();
- int currentImeUid = LocalServices.getService(PackageManagerInternal.class)
- .getPackageUidInternal(packageName, 0 /* flags */, currentUserId);
- if (currentImeUid < 0) {
- Log.e(TAG, "updateCurrentImeUid() could not find UID for package: " + packageName);
- return;
- }
-
- if (currentImeUid != mCurrentImeUid || forceUpdate) {
- mAudioSystem.setCurrentImeUid(currentImeUid);
- mCurrentImeUid = currentImeUid;
- }
- }
-
private void readPersistedSettings() {
if (!mSystemServer.isPrivileged()) {
return;
@@ -1703,7 +1681,6 @@
sendEncodedSurroundMode(cr, "readPersistedSettings");
sendEnabledSurroundFormats(cr, true);
updateAssistantUId(true);
- updateCurrentImeUid(true);
AudioSystem.setRttEnabled(mRttEnabled);
}
@@ -3590,11 +3567,9 @@
}
public void binderDied() {
- int oldModeOwnerPid;
int newModeOwnerPid = 0;
synchronized (mDeviceBroker.mSetModeLock) {
Log.w(TAG, "setMode() client died");
- oldModeOwnerPid = getModeOwnerPid();
int index = mSetModeDeathHandlers.indexOf(this);
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
@@ -3604,9 +3579,7 @@
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
- mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid);
- }
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
}
public int getPid() {
@@ -3658,17 +3631,20 @@
return;
}
- int oldModeOwnerPid;
int newModeOwnerPid;
synchronized (mDeviceBroker.mSetModeLock) {
if (mode == AudioSystem.MODE_CURRENT) {
mode = mMode;
}
- oldModeOwnerPid = getModeOwnerPid();
+ int oldModeOwnerPid = getModeOwnerPid();
// Do not allow changing mode if a call is active and the requester
- // does not have permission to modify phone state or is not the mode owner.
- if (((mMode == AudioSystem.MODE_IN_CALL)
- || (mMode == AudioSystem.MODE_IN_COMMUNICATION))
+ // does not have permission to modify phone state or is not the mode owner,
+ // unless returning to NORMAL mode (will not change current mode owner) or
+ // not changing mode in which case the mode owner will reflect the last
+ // requester of current mode
+ if (!((mode == mMode) || (mode == AudioSystem.MODE_NORMAL))
+ && ((mMode == AudioSystem.MODE_IN_CALL)
+ || (mMode == AudioSystem.MODE_IN_COMMUNICATION))
&& !(hasModifyPhoneStatePermission || (oldModeOwnerPid == callingPid))) {
Log.w(TAG, "setMode(" + mode + ") from pid=" + callingPid
+ ", uid=" + Binder.getCallingUid()
@@ -3681,9 +3657,7 @@
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
- mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid);
- }
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
}
// setModeInt() returns a valid PID if the audio mode was successfully set to
@@ -3960,32 +3934,18 @@
}
/** @see AudioManager#setSpeakerphoneOn(boolean) */
- public void setSpeakerphoneOn(boolean on){
+ public void setSpeakerphoneOn(IBinder cb, boolean on) {
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return;
}
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- synchronized (mSetModeDeathHandlers) {
- for (SetModeDeathHandler h : mSetModeDeathHandlers) {
- if (h.getMode() == AudioSystem.MODE_IN_CALL) {
- Log.w(TAG, "getMode is call, Permission Denial: setSpeakerphoneOn from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
- return;
- }
- }
- }
- }
-
// for logging only
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
.append(") from u/pid:").append(uid).append("/")
.append(pid).toString();
- final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+ final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(cb, pid, on, eventSource);
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE
+ MediaMetrics.SEPARATOR + "setSpeakerphoneOn")
.setUid(uid)
@@ -6213,8 +6173,6 @@
mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
- mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
}
@Override
@@ -6238,7 +6196,6 @@
updateEncodedSurroundOutput();
sendEnabledSurroundFormats(mContentResolver, mSurroundModeChanged);
updateAssistantUId(false);
- updateCurrentImeUid(false);
}
}
@@ -7365,10 +7322,32 @@
return false;
}
boolean suppress = false;
- if (resolvedStream != AudioSystem.STREAM_MUSIC && mController != null) {
+ // Intended behavior:
+ // 1/ if the stream is not the default UI stream, do not suppress (as it is not involved
+ // in bringing up the UI)
+ // 2/ if the resolved and default stream is MUSIC, and media is playing, do not suppress
+ // 3/ otherwise suppress the first adjustments that occur during the "long press
+ // timeout" interval. Note this is true regardless of whether this is a "real long
+ // press" (where the user keeps pressing on the volume button), or repeated single
+ // presses (here we don't know if we are in a real long press, or repeated fast
+ // button presses).
+ // Once the long press timeout occurs (mNextLongPress reset to 0), do not suppress.
+ // Example: for a default and resolved stream of MUSIC, this allows modifying rapidly
+ // the volume when media is playing (whether by long press or repeated individual
+ // presses), or to bring up the volume UI when media is not playing, in order to make
+ // another change (e.g. switch ringer modes) without changing media volume.
+ if (resolvedStream == DEFAULT_VOL_STREAM_NO_PLAYBACK && mController != null) {
+ // never suppress media vol adjustement during media playback
+ if (resolvedStream == AudioSystem.STREAM_MUSIC
+ && AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, mLongPressTimeout))
+ {
+ // media is playing, adjust the volume right away
+ return false;
+ }
+
final long now = SystemClock.uptimeMillis();
if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
- // ui will become visible
+ // UI is not visible yet, adjustment is ignored
if (mNextLongPress < now) {
mNextLongPress = now + mLongPressTimeout;
}
@@ -7558,6 +7537,19 @@
AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setInputMethodServiceUid(int uid) {
+ synchronized (mInputMethodServiceUidLock) {
+ if (mInputMethodServiceUid != uid) {
+ mAudioSystem.setCurrentImeUid(uid);
+ mInputMethodServiceUid = uid;
+ }
+ }
+ }
}
//==========================================================================================
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 0654f86..b4c41b2 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -38,6 +38,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
@@ -131,6 +132,26 @@
}
}
+ /**
+ * Returns a string representation of the scoAudioState.
+ */
+ public static String scoAudioStateToString(int scoAudioState) {
+ switch (scoAudioState) {
+ case SCO_STATE_INACTIVE:
+ return "SCO_STATE_INACTIVE";
+ case SCO_STATE_ACTIVATE_REQ:
+ return "SCO_STATE_ACTIVATE_REQ";
+ case SCO_STATE_ACTIVE_EXTERNAL:
+ return "SCO_STATE_ACTIVE_EXTERNAL";
+ case SCO_STATE_ACTIVE_INTERNAL:
+ return "SCO_STATE_ACTIVE_INTERNAL";
+ case SCO_STATE_DEACTIVATING:
+ return "SCO_STATE_DEACTIVATING";
+ default:
+ return "SCO_STATE_(" + scoAudioState + ")";
+ }
+ }
+
//----------------------------------------------------------------------
/*package*/ static class BluetoothA2dpDeviceInfo {
private final @NonNull BluetoothDevice mBtDevice;
@@ -307,8 +328,15 @@
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
- // startBluetoothSco called after stopBluetoothSco
- if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+ // There are two cases where we want to immediately reconnect audio:
+ // 1) If a new start request was received while disconnecting: this was
+ // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ.
+ // 2) If audio was connected then disconnected via Bluetooth APIs and
+ // we still have pending activation requests by apps: this is indicated by
+ // state SCO_STATE_ACTIVE_EXTERNAL and the mScoClients list not empty.
+ if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
+ || (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL
+ && !mScoClients.isEmpty())) {
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
&& connectBluetoothScoAudioHelper(mBluetoothHeadset,
mBluetoothHeadsetDevice, mScoAudioMode)) {
@@ -318,7 +346,9 @@
}
}
// Tear down SCO if disconnected from external
- clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
+ if (mScoAudioState == SCO_STATE_DEACTIVATING) {
+ clearAllScoClients(0, false);
+ }
mScoAudioState = SCO_STATE_INACTIVE;
break;
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
@@ -349,14 +379,11 @@
* @return false if SCO isn't connected
*/
/*package*/ synchronized boolean isBluetoothScoOn() {
- if ((mBluetoothHeadset != null)
- && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
- Log.w(TAG, "isBluetoothScoOn(true) returning false because "
- + mBluetoothHeadsetDevice + " is not in audio connected mode");
+ if (mBluetoothHeadset == null) {
return false;
}
- return true;
+ return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ == BluetoothHeadset.STATE_AUDIO_CONNECTED;
}
/**
@@ -1001,4 +1028,20 @@
return "ENCODING_BT_CODEC_TYPE(" + btCodecType + ")";
}
}
+
+ //------------------------------------------------------------
+ /*package*/ void dump(PrintWriter pw, String prefix) {
+ pw.println("\n" + prefix + "mBluetoothHeadset: " + mBluetoothHeadset);
+ pw.println(prefix + "mBluetoothHeadsetDevice: " + mBluetoothHeadsetDevice);
+ pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState));
+ pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode));
+ pw.println(prefix + "Sco clients:");
+ mScoClients.forEach((cl) -> {
+ pw.println(" " + prefix + "pid: " + cl.getPid() + " cb: " + cl.getBinder()); });
+
+ pw.println("\n" + prefix + "mHearingAid: " + mHearingAid);
+ pw.println(prefix + "mA2dp: " + mA2dp);
+ pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported);
+ }
+
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 70fbca5..7e28e94 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -170,6 +170,8 @@
final String mOpPackageName;
// Info to be shown on BiometricDialog when all cookies are returned.
final Bundle mBundle;
+ // Random id associated to this AuthSession
+ final int mSysUiSessionId;
final int mCallingUid;
final int mCallingPid;
final int mCallingUserId;
@@ -203,11 +205,13 @@
mClientReceiver = receiver;
mOpPackageName = opPackageName;
mBundle = bundle;
+ mSysUiSessionId = mRandom.nextInt();
mCallingUid = callingUid;
mCallingPid = callingPid;
mCallingUserId = callingUserId;
mModality = modality;
mRequireConfirmation = requireConfirmation;
+ Slog.d(TAG, "New AuthSession, mSysUiSessionId: " + mSysUiSessionId);
}
boolean isCrypto() {
@@ -1457,7 +1461,8 @@
false /* requireConfirmation */,
mCurrentAuthSession.mUserId,
mCurrentAuthSession.mOpPackageName,
- mCurrentAuthSession.mSessionId);
+ mCurrentAuthSession.mSessionId,
+ mCurrentAuthSession.mSysUiSessionId);
} else {
mPendingAuthSession.mClientReceiver.onError(modality, error, vendorCode);
mPendingAuthSession = null;
@@ -1680,7 +1685,8 @@
mStatusBarService.showAuthenticationDialog(mCurrentAuthSession.mBundle,
mInternalReceiver, modality, requireConfirmation, userId,
mCurrentAuthSession.mOpPackageName,
- mCurrentAuthSession.mSessionId);
+ mCurrentAuthSession.mSessionId,
+ mCurrentAuthSession.mSysUiSessionId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
@@ -1766,7 +1772,8 @@
false /* requireConfirmation */,
mCurrentAuthSession.mUserId,
mCurrentAuthSession.mOpPackageName,
- sessionId);
+ sessionId,
+ mCurrentAuthSession.mSysUiSessionId);
} else {
mPendingAuthSession.mState = STATE_AUTH_CALLED;
for (AuthenticatorWrapper authenticator : mAuthenticators) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 808f8c21..5a6ab4e5 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -978,6 +978,10 @@
}
protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
+ if (callback == null) {
+ Slog.w(getTag(), "Null LockoutResetCallback");
+ return;
+ }
mHandler.post(() -> {
final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
if (!mLockoutMonitors.contains(monitor)) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 8520f5a..d90f3af 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -330,6 +330,7 @@
@Override
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
throws RemoteException {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
FingerprintService.super.addLockoutResetCallback(callback);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 15628f0..37b2de1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -168,6 +168,9 @@
// Obtained by ConnectivityService and merged into NetworkAgent-provided information.
public CaptivePortalData captivePortalData;
+ // The UID of the remote entity that created this Network.
+ public final int creatorUid;
+
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
// network is taken down. This usually only happens to the default network. Lingering ends with
@@ -268,7 +271,8 @@
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
- IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
+ IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
+ int creatorUid) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -282,6 +286,7 @@
mHandler = handler;
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
+ this.creatorUid = creatorUid;
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c54ebf8..3c05080 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -92,7 +92,7 @@
private final AppRequestObserver mAppRequestObserver;
private final SettingsObserver mSettingsObserver;
private final DisplayObserver mDisplayObserver;
- private final BrightnessObserver mBrightnessObserver;
+ private BrightnessObserver mBrightnessObserver;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
@@ -460,6 +460,21 @@
mVotesByDisplay = votesByDisplay;
}
+ @VisibleForTesting
+ void injectBrightnessObserver(BrightnessObserver brightnessObserver) {
+ mBrightnessObserver = brightnessObserver;
+ }
+
+ @VisibleForTesting
+ DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
+ float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
+ synchronized (mLock) {
+ mSettingsObserver.updateRefreshRateSettingLocked(
+ minRefreshRate, peakRefreshRate, defaultRefreshRate);
+ return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY);
+ }
+ }
+
/**
* Listens for changes refresh rate coordination.
*/
@@ -666,14 +681,18 @@
@VisibleForTesting
static final class Vote {
+ // DEFAULT_FRAME_RATE votes for [0, DEFAULT]. As the lowest priority vote, it's overridden
+ // by all other considerations. It acts to set a default frame rate for a device.
+ public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0;
+
// LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
// If the higher voters result is a range, it will fix the rate to a single choice.
// It's used to avoid rate switch in certain conditions.
- public static final int PRIORITY_LOW_BRIGHTNESS = 0;
+ public static final int PRIORITY_LOW_BRIGHTNESS = 1;
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
- public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1;
+ public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 2;
// We split the app request into different priorities in case we can satisfy one desire
// without the other.
@@ -683,20 +702,20 @@
// @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
// System also forces some apps like blacklisted app to run at a lower refresh rate.
// @see android.R.array#config_highRefreshRateBlacklist
- public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 2;
- public static final int PRIORITY_APP_REQUEST_SIZE = 3;
+ public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 3;
+ public static final int PRIORITY_APP_REQUEST_SIZE = 4;
// SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
// of low priority voters. It votes [0, max(PEAK, MIN)]
- public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4;
+ public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 5;
// LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
- public static final int PRIORITY_LOW_POWER_MODE = 5;
+ public static final int PRIORITY_LOW_POWER_MODE = 6;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
- public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
+ public static final int MIN_PRIORITY = PRIORITY_DEFAULT_REFRESH_RATE;
public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE;
// The cutoff for the app request refresh rate range. Votes with priorities lower than this
@@ -740,6 +759,8 @@
public static String priorityToString(int priority) {
switch (priority) {
+ case PRIORITY_DEFAULT_REFRESH_RATE:
+ return "PRIORITY_DEFAULT_REFRESH_RATE";
case PRIORITY_LOW_BRIGHTNESS:
return "PRIORITY_LOW_BRIGHTNESS";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
@@ -776,12 +797,15 @@
private final Context mContext;
private float mDefaultPeakRefreshRate;
+ private float mDefaultRefreshRate;
SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
super(handler);
mContext = context;
mDefaultPeakRefreshRate = (float) context.getResources().getInteger(
R.integer.config_defaultPeakRefreshRate);
+ mDefaultRefreshRate =
+ (float) context.getResources().getInteger(R.integer.config_defaultRefreshRate);
}
public void observe() {
@@ -849,17 +873,48 @@
Settings.System.MIN_REFRESH_RATE, 0f);
float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
+ updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
+ }
- updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
- Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate)));
+ private void updateRefreshRateSettingLocked(
+ float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
+ // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
+ // used to predict if we're going to be doing frequent refresh rate switching, and if
+ // so, enable the brightness observer. The logic here is more complicated and fragile
+ // than necessary, and we should improve it. See b/156304339 for more info.
+ Vote peakVote = peakRefreshRate == 0f
+ ? null
+ : Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate));
+ updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, peakVote);
updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
Vote.forRefreshRates(minRefreshRate, Float.POSITIVE_INFINITY));
+ Vote defaultVote =
+ defaultRefreshRate == 0f ? null : Vote.forRefreshRates(0f, defaultRefreshRate);
+ updateVoteLocked(Vote.PRIORITY_DEFAULT_REFRESH_RATE, defaultVote);
- mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate);
+ float maxRefreshRate;
+ if (peakRefreshRate == 0f && defaultRefreshRate == 0f) {
+ // We require that at least one of the peak or default refresh rate values are
+ // set. The brightness observer requires that we're able to predict whether or not
+ // we're going to do frequent refresh rate switching, and with the way the code is
+ // currently written, we need either a default or peak refresh rate value for that.
+ Slog.e(TAG, "Default and peak refresh rates are both 0. One of them should be set"
+ + " to a valid value.");
+ maxRefreshRate = minRefreshRate;
+ } else if (peakRefreshRate == 0f) {
+ maxRefreshRate = defaultRefreshRate;
+ } else if (defaultRefreshRate == 0f) {
+ maxRefreshRate = peakRefreshRate;
+ } else {
+ maxRefreshRate = Math.min(defaultRefreshRate, peakRefreshRate);
+ }
+
+ mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, maxRefreshRate);
}
public void dumpLocked(PrintWriter pw) {
pw.println(" SettingsObserver");
+ pw.println(" mDefaultRefreshRate: " + mDefaultRefreshRate);
pw.println(" mDefaultPeakRefreshRate: " + mDefaultPeakRefreshRate);
}
}
@@ -1014,7 +1069,8 @@
* {@link R.array#config_brightnessThresholdsOfPeakRefreshRate} and
* {@link R.array#config_ambientThresholdsOfPeakRefreshRate}.
*/
- private class BrightnessObserver extends ContentObserver {
+ @VisibleForTesting
+ public class BrightnessObserver extends ContentObserver {
// TODO: brightnessfloat: change this to the float setting
private final Uri mDisplayBrightnessSetting =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index bafeb77..9411c562 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1067,12 +1067,22 @@
mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f;
final boolean brightnessIsTemporary =
mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
- if (initialRampSkip || hasBrightnessBuckets
- || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
- animateScreenBrightness(brightnessState, SCREEN_ANIMATION_RATE_MINIMUM);
- } else {
- animateScreenBrightness(brightnessState,
- slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
+ // We only want to animate the brightness if it is between 0.0f and 1.0f.
+ // brightnessState can contain the values -1.0f and NaN, which we do not want to
+ // animate to. To avoid this, we check the value first.
+ // If the brightnessState is off (-1.0f) we still want to animate to the minimum
+ // brightness (0.0f) to accommodate for LED displays, which can appear bright to the
+ // user even when the display is all black.
+ float animateValue = brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT
+ ? PowerManager.BRIGHTNESS_MIN : brightnessState;
+ if (isValidBrightnessValue(animateValue)) {
+ if (initialRampSkip || hasBrightnessBuckets
+ || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
+ animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM);
+ } else {
+ animateScreenBrightness(animateValue,
+ slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
+ }
}
if (!brightnessIsTemporary) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 24e1b4e..4b6430d 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -146,7 +146,7 @@
/**
* Sets the display brightness.
*
- * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
+ * @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest).
*/
public void setScreenBrightness(float brightness) {
if (mScreenBrightness != brightness) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 4f5a02a..2a65b33 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -201,7 +201,6 @@
private SurfaceControl.DisplayConfig[] mDisplayConfigs;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
- private boolean mHalBrightnessSupport;
private DisplayDeviceConfig mDisplayDeviceConfig;
@@ -225,7 +224,6 @@
}
mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken);
mGameContentTypeSupported = SurfaceControl.getGameContentTypeSupport(displayToken);
- mHalBrightnessSupport = SurfaceControl.getDisplayBrightnessSupport(displayToken);
mDisplayDeviceConfig = null;
// Defer configuration file loading
BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
@@ -717,11 +715,10 @@
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+ "id=" + physicalDisplayId + ", brightness=" + brightness + ")");
try {
- // TODO: make it float
if (isHalBrightnessRangeSpecified()) {
brightness = displayBrightnessToHalBrightness(
- BrightnessSynchronizer.brightnessFloatToInt(getContext(),
- brightness));
+ BrightnessSynchronizer.brightnessFloatToIntRange(
+ getContext(), brightness));
}
if (mBacklight != null) {
mBacklight.setBrightness(brightness);
@@ -744,12 +741,13 @@
* Hal brightness space if the HAL brightness space has been provided via
* a display device configuration file.
*/
- private float displayBrightnessToHalBrightness(int brightness) {
+ private float displayBrightnessToHalBrightness(float brightness) {
if (!isHalBrightnessRangeSpecified()) {
return PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
- if (brightness == 0) {
+ if (BrightnessSynchronizer.floatEquals(
+ brightness, PowerManager.BRIGHTNESS_OFF)) {
return PowerManager.BRIGHTNESS_OFF_FLOAT;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 5541b11..1810963 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -44,9 +44,6 @@
public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
private static final String TAG = "HdmiCecLocalDevicePlayback";
- private static final boolean WAKE_ON_HOTPLUG =
- SystemProperties.getBoolean(Constants.PROPERTY_WAKE_ON_HOTPLUG, false);
-
private static final boolean SET_MENU_LANGUAGE =
HdmiProperties.set_menu_language().orElse(false);
@@ -152,9 +149,6 @@
assertRunOnServiceThread();
mCecMessageCache.flushAll();
// We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
- if (WAKE_ON_HOTPLUG && connected && mService.isPowerStandbyOrTransient()) {
- mService.wakeUp();
- }
if (!connected) {
getWakeLock().release();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 53f9ebc..9de95ab 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2207,13 +2207,13 @@
@Override
public void setHdmiCecVolumeControlEnabled(final boolean isHdmiCecVolumeControlEnabled) {
enforceAccessPermission();
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- HdmiControlService.this.setHdmiCecVolumeControlEnabled(
- isHdmiCecVolumeControlEnabled);
- }
- });
+ long token = Binder.clearCallingIdentity();
+ try {
+ HdmiControlService.this.setHdmiCecVolumeControlEnabled(
+ isHdmiCecVolumeControlEnabled);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
@@ -3014,7 +3014,6 @@
}
void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
- assertRunOnServiceThread();
synchronized (mLock) {
mHdmiCecVolumeControlEnabled = isHdmiCecVolumeControlEnabled;
@@ -3030,7 +3029,6 @@
}
boolean isHdmiCecVolumeControlEnabled() {
- assertRunOnServiceThread();
synchronized (mLock) {
return mHdmiCecVolumeControlEnabled;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index d49d4b2..de13bd8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -45,6 +45,12 @@
}
/**
+ * Called by the power manager to tell the input method manager whether it
+ * should start watching for wake events.
+ */
+ public abstract void setInteractive(boolean interactive);
+
+ /**
* Hides the current input method, if visible.
*/
public abstract void hideCurrentInputMethod(@SoftInputShowHideReason int reason);
@@ -108,6 +114,10 @@
private static final InputMethodManagerInternal NOP =
new InputMethodManagerInternal() {
@Override
+ public void setInteractive(boolean interactive) {
+ }
+
+ @Override
public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index b949d6b..52116a0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -56,6 +56,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
@@ -67,6 +68,7 @@
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
+import android.media.AudioManagerInternal;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -223,6 +225,8 @@
static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
+ static final int MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE = 7000;
+
static final long TIME_TO_RECONNECT = 3 * 1000;
static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
@@ -308,6 +312,7 @@
final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager;
final WindowManagerInternal mWindowManagerInternal;
+ final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
private final DisplayManagerInternal mDisplayManagerInternal;
final HandlerCaller mCaller;
@@ -320,6 +325,16 @@
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
+ /**
+ * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
+ *
+ * <p>This field is used only within {@link #handleMessage(Message)} hence synchronization is
+ * not necessary.</p>
+ */
+ @Nullable
+ private AudioManagerInternal mAudioManagerInternal = null;
+
+
// All known input methods. mMethodMap also serves as the global
// lock for this class.
final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
@@ -643,6 +658,11 @@
IInputMethod mCurMethod;
/**
+ * If not {@link Process#INVALID_UID}, then the UID of {@link #mCurIntent}.
+ */
+ int mCurMethodUid = Process.INVALID_UID;
+
+ /**
* Time that we last initiated a bind to the input method, to determine
* if we should try to disconnect and reconnect to it.
*/
@@ -1625,6 +1645,7 @@
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
@@ -2521,11 +2542,26 @@
return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
}
+ @AnyThread
+ private void scheduleNotifyImeUidToAudioService(int uid) {
+ mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE);
+ mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget();
+ }
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
+ final String curMethodPackage = mCurIntent.getComponent().getPackageName();
+ final int curMethodUid = mPackageManagerInternal.getPackageUidInternal(
+ curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
+ if (curMethodUid < 0) {
+ Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
+ mCurMethodUid = Process.INVALID_UID;
+ } else {
+ mCurMethodUid = curMethodUid;
+ }
if (mCurToken == null) {
Slog.w(TAG, "Service connected without a token!");
unbindCurrentMethodLocked();
@@ -2535,6 +2571,7 @@
// Dispatch display id for InputMethodService to update context display.
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
+ scheduleNotifyImeUidToAudioService(mCurMethodUid);
if (mCurClient != null) {
clearClientSessionLocked(mCurClient);
requestClientSessionLocked(mCurClient);
@@ -2656,6 +2693,8 @@
finishSessionLocked(mEnabledSession);
mEnabledSession = null;
mCurMethod = null;
+ mCurMethodUid = Process.INVALID_UID;
+ scheduleNotifyImeUidToAudioService(mCurMethodUid);
}
if (mStatusBar != null) {
mStatusBar.setIconVisibility(mSlotIme, false);
@@ -4202,6 +4241,9 @@
+ ((ClientState)msg.obj).uid);
}
return true;
+ case MSG_SET_INTERACTIVE:
+ handleSetInteractive(msg.arg1 != 0);
+ return true;
case MSG_REPORT_FULLSCREEN_MODE: {
final boolean fullscreen = msg.arg1 != 0;
final ClientState clientState = (ClientState)msg.obj;
@@ -4259,7 +4301,7 @@
}
// ---------------------------------------------------------------
- case MSG_INLINE_SUGGESTIONS_REQUEST:
+ case MSG_INLINE_SUGGESTIONS_REQUEST: {
args = (SomeArgs) msg.obj;
final InlineSuggestionsRequestInfo requestInfo =
(InlineSuggestionsRequestInfo) args.arg2;
@@ -4271,11 +4313,38 @@
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
}
+ args.recycle();
return true;
+ }
+
+ // ---------------------------------------------------------------
+ case MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE: {
+ if (mAudioManagerInternal == null) {
+ mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+ }
+ if (mAudioManagerInternal != null) {
+ mAudioManagerInternal.setInputMethodServiceUid(msg.arg1 /* uid */);
+ }
+ return true;
+ }
}
return false;
}
+ private void handleSetInteractive(final boolean interactive) {
+ synchronized (mMethodMap) {
+ mIsInteractive = interactive;
+ updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
+
+ // Inform the current client of the change in active status
+ if (mCurClient != null && mCurClient.client != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
+ MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
+ mCurClient));
+ }
+ }
+ }
+
private boolean chooseNewDefaultIMELocked() {
final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
mSettings.getEnabledInputMethodListLocked());
@@ -4885,6 +4954,13 @@
}
@Override
+ public void setInteractive(boolean interactive) {
+ // Do everything in handler so as not to block the caller.
+ mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
+ .sendToTarget();
+ }
+
+ @Override
public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 0b73e4f..2129e9b 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -171,6 +171,11 @@
LocalServices.addService(InputMethodManagerInternal.class,
new InputMethodManagerInternal() {
@Override
+ public void setInteractive(boolean interactive) {
+ reportNotSupported();
+ }
+
+ @Override
public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
reportNotSupported();
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 2cae1d6..817902d 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -190,6 +190,9 @@
public void updateRuleSet(
String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) {
String ruleProvider = getCallerPackageNameOrThrow(Binder.getCallingUid());
+ if (DEBUG_INTEGRITY_COMPONENT) {
+ Slog.i(TAG, String.format("Calling rule provider name is: %s.", ruleProvider));
+ }
mHandler.post(
() -> {
@@ -201,6 +204,9 @@
success = false;
}
+ if (DEBUG_INTEGRITY_COMPONENT) {
+ Slog.i(TAG, String.format("Successfully pushed rule set: %s", version));
+ }
FrameworkStatsLog.write(
FrameworkStatsLog.INTEGRITY_RULES_PUSHED,
success,
@@ -571,7 +577,7 @@
// APK signatures is already verified elsewhere in PackageManager. We do not need to
// verify it again since it could cause a timeout for large APKs.
pkg.setSigningDetails(
- ParsingPackageUtils.collectCertificates(pkg, /* skipVerify= */ true));
+ ParsingPackageUtils.getSigningDetails(pkg, /* skipVerify= */ true));
return PackageInfoUtils.generate(
pkg,
null,
@@ -673,9 +679,6 @@
// Identify the package names in the caller list.
List<String> callingPackageNames = getPackageListForUid(callingUid);
- if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, String.format("Calling packages are: ", callingPackageNames));
- }
// Find the intersection between the allowed and calling packages. Ideally, we will have
// at most one package name here. But if we have more, it is fine.
@@ -685,10 +688,7 @@
allowedCallingPackages.add(packageName);
}
}
- if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG,
- String.format("Calling rule pusher packages are: ", allowedCallingPackages));
- }
+
return allowedCallingPackages.isEmpty() ? null : allowedCallingPackages.get(0);
}
@@ -706,9 +706,6 @@
Arrays.asList(
mContext.getResources()
.getStringArray(R.array.config_integrityRuleProviderPackages));
- if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, String.format("Rule provider list contains: %s", integrityRuleProviders));
- }
// Filter out the rule provider packages that are not system apps.
List<String> systemAppRuleProviders = new ArrayList<>();
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 8888108..c4f8441 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -41,9 +41,12 @@
import com.android.internal.BrightnessSynchronizer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -174,6 +177,36 @@
closeSessionInternal(token);
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+
+ synchronized (LightsService.this) {
+ if (mVintfLights != null) {
+ pw.println("Service: aidl (" + mVintfLights.get() + ")");
+ } else {
+ pw.println("Service: hidl");
+ }
+
+ pw.println("Lights:");
+ for (int i = 0; i < mLightsById.size(); i++) {
+ final LightImpl light = mLightsById.valueAt(i);
+ pw.println(String.format(" Light id=%d ordinal=%d color=%08x",
+ light.mHwLight.id, light.mHwLight.ordinal, light.getColor()));
+ }
+
+ pw.println("Session clients:");
+ for (Session session : mSessions) {
+ pw.println(" Session token=" + session.mToken);
+ for (int i = 0; i < session.mRequests.size(); i++) {
+ pw.println(String.format(" Request id=%d color=%08x",
+ session.mRequests.keyAt(i),
+ session.mRequests.valueAt(i).getColor()));
+ }
+ }
+ }
+ }
+
private void closeSessionInternal(IBinder token) {
synchronized (LightsService.this) {
final Session session = getSessionLocked(token);
diff --git a/services/core/java/com/android/server/lights/TEST_MAPPING b/services/core/java/com/android/server/lights/TEST_MAPPING
new file mode 100644
index 0000000..f868ea0
--- /dev/null
+++ b/services/core/java/com/android/server/lights/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsHardwareTestCases",
+ "options": [
+ {"include-filter": "com.android.hardware.lights"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.lights"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 4f8708a..ccbe96f 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -69,6 +69,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.ICancellationSignal;
+import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
@@ -2600,6 +2601,14 @@
}
@Override
+ public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out,
+ ParcelFileDescriptor err, String[] args) {
+ return new LocationShellCommand(this).exec(
+ this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
+ args);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
return;
@@ -2658,8 +2667,7 @@
mRequestStatistics.statistics);
for (Map.Entry<PackageProviderKey, PackageStatistics> entry
: sorted.entrySet()) {
- PackageProviderKey key = entry.getKey();
- ipw.println(key.mPackageName + ": " + key.mProviderName + ": " + entry.getValue());
+ ipw.println(entry.getKey() + ": " + entry.getValue());
}
ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index dcdf48b..e629b42 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.util.Log;
@@ -25,6 +26,7 @@
import com.android.internal.util.IndentingPrintWriter;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Objects;
@@ -121,14 +123,30 @@
this.mProviderName = providerName;
}
+ @NonNull
+ @Override
+ public String toString() {
+ return mProviderName + ": " + mPackageName
+ + (mFeatureId == null ? "" : ": " + mFeatureId);
+ }
+
+ /**
+ * Sort by provider, then package, then feature
+ */
@Override
public int compareTo(PackageProviderKey other) {
final int providerCompare = mProviderName.compareTo(other.mProviderName);
if (providerCompare != 0) {
return providerCompare;
- } else {
- return mProviderName.compareTo(other.mProviderName);
}
+
+ final int packageCompare = mPackageName.compareTo(other.mPackageName);
+ if (packageCompare != 0) {
+ return packageCompare;
+ }
+
+ return Objects.compare(mFeatureId, other.mFeatureId, Comparator
+ .nullsFirst(String::compareTo));
}
@Override
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
new file mode 100644
index 0000000..909873f
--- /dev/null
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -0,0 +1,92 @@
+/*
+ * 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.location;
+
+import android.os.BasicShellCommandHandler;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * Interprets and executes 'adb shell cmd location [args]'.
+ */
+class LocationShellCommand extends BasicShellCommandHandler {
+
+ private final LocationManagerService mService;
+
+ LocationShellCommand(LocationManagerService service) {
+ mService = Objects.requireNonNull(service);
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(null);
+ }
+
+ switch (cmd) {
+ case "set-location-enabled": {
+ int userId = parseUserId();
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ mService.setLocationEnabledForUser(enabled, userId);
+ return 0;
+ }
+ case "send-extra-command": {
+ String provider = getNextArgRequired();
+ String command = getNextArgRequired();
+ mService.sendExtraCommand(provider, command, null);
+ return 0;
+ }
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int parseUserId() {
+ final String option = getNextOption();
+ if (option != null) {
+ if (option.equals("--user")) {
+ return UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException(
+ "Expected \"--user\" option, but got \"" + option + "\" instead");
+ }
+ }
+
+ return UserHandle.USER_CURRENT_OR_SELF;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Location service commands:");
+ pw.println(" help or -h");
+ pw.println(" Print this help text.");
+ pw.println(" set-location-enabled [--user <USER_ID>] true|false");
+ pw.println(" Sets the master location switch enabled state.");
+ pw.println(" send-extra-command <PROVIDER> <COMMAND>");
+ pw.println(" Sends the given extra command to the given provider.");
+ pw.println();
+ pw.println(" Common commands that may be supported by the gps provider, depending on");
+ pw.println(" hardware and software configurations:");
+ pw.println(" delete_aiding_data - requests deletion of any predictive aiding data");
+ pw.println(" force_time_injection - requests NTP time injection to chipset");
+ pw.println(" force_psds_injection - "
+ + "requests predictive aiding data injection to chipset");
+ }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
index 75fd7dc..927fcfb 100644
--- a/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
@@ -630,7 +630,7 @@
}
Notification.Builder builder = new Notification.Builder(mContext,
- SystemNotificationChannels.NETWORK_ALERTS)
+ SystemNotificationChannels.NETWORK_STATUS)
.setSmallIcon(R.drawable.stat_sys_gps_on)
.setCategory(Notification.CATEGORY_SYSTEM)
.setVisibility(Notification.VISIBILITY_SECRET)
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 93d45c8..1a8de97 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -312,7 +312,7 @@
}
void register(LockSettingsStrongAuth strongAuth) {
- strongAuth.registerStrongAuthTracker(this.mStub);
+ strongAuth.registerStrongAuthTracker(getStub());
}
}
@@ -1972,7 +1972,13 @@
public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
long challenge, int userId) {
checkPasswordReadPermission(userId);
- return doVerifyCredential(credential, CHALLENGE_FROM_CALLER, challenge, userId,
+ @ChallengeType int challengeType = CHALLENGE_FROM_CALLER;
+ if (challenge == 0) {
+ Slog.w(TAG, "VerifyCredential called with challenge=0");
+ challengeType = CHALLENGE_NONE;
+
+ }
+ return doVerifyCredential(credential, challengeType, challenge, userId,
null /* progressCallback */);
}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 3cf22c8..6acfd45 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -28,9 +28,12 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
+import android.media.AudioSystem;
import android.media.MediaRoute2Info;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import com.android.internal.R;
@@ -54,6 +57,9 @@
@SuppressWarnings("WeakerAccess") /* synthetic access */
BluetoothHearingAid mHearingAidProfile;
+ // Route type -> volume map
+ private final SparseIntArray mVolumeMap = new SparseIntArray();
+
private final Context mContext;
private final BluetoothAdapter mBluetoothAdapter;
private final BluetoothRoutesUpdatedListener mListener;
@@ -163,7 +169,9 @@
for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) {
if (device.isConnected()) {
BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
- mBluetoothRoutes.put(device.getAddress(), newBtRoute);
+ if (newBtRoute.connectedProfiles.size() > 0) {
+ mBluetoothRoutes.put(device.getAddress(), newBtRoute);
+ }
}
}
}
@@ -191,11 +199,30 @@
return routes;
}
- boolean setSelectedRouteVolume(int volume) {
- if (mSelectedRoute == null) return false;
+ /**
+ * Updates the volume for {@link AudioManager#getDevicesForStream(int) devices}.
+ *
+ * @return true if devices can be handled by the provider.
+ */
+ public boolean updateVolumeForDevices(int devices, int volume) {
+ int routeType;
+ if ((devices & (AudioSystem.DEVICE_OUT_HEARING_AID)) != 0) {
+ routeType = MediaRoute2Info.TYPE_HEARING_AID;
+ } else if ((devices & (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP
+ | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
+ | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
+ routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ } else {
+ return false;
+ }
+ mVolumeMap.put(routeType, volume);
+ if (mSelectedRoute == null || mSelectedRoute.route.getType() != routeType) {
+ return true;
+ }
mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route)
.setVolume(volume)
.build();
+ notifyBluetoothRoutesUpdated();
return true;
}
@@ -208,17 +235,32 @@
private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) {
BluetoothRouteInfo newBtRoute = new BluetoothRouteInfo();
newBtRoute.btDevice = device;
- // Current / Max volume will be set when connected.
+ // Current volume will be set when connected.
// TODO: Is there any BT device which has fixed volume?
- newBtRoute.route = new MediaRoute2Info.Builder(device.getAddress(), device.getName())
+ String deviceName = device.getName();
+ if (TextUtils.isEmpty(deviceName)) {
+ deviceName = mContext.getResources().getText(R.string.unknownName).toString();
+ }
+ int type = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ newBtRoute.connectedProfiles = new SparseBooleanArray();
+ if (mA2dpProfile != null && mA2dpProfile.getConnectedDevices().contains(device)) {
+ newBtRoute.connectedProfiles.put(BluetoothProfile.A2DP, true);
+ }
+ if (mHearingAidProfile != null
+ && mHearingAidProfile.getConnectedDevices().contains(device)) {
+ newBtRoute.connectedProfiles.put(BluetoothProfile.HEARING_AID, true);
+ type = MediaRoute2Info.TYPE_HEARING_AID;
+ }
+
+ newBtRoute.route = new MediaRoute2Info.Builder(device.getAddress(), deviceName)
.addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
.setDescription(mContext.getResources().getText(
R.string.bluetooth_a2dp_audio_route_name).toString())
- .setType(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)
+ .setType(type)
.setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
.build();
- newBtRoute.connectedProfiles = new SparseBooleanArray();
return newBtRoute;
}
@@ -235,13 +277,10 @@
// Update volume when the connection state is changed.
MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.route)
.setConnectionState(state);
- builder.setType(btRoute.connectedProfiles.get(BluetoothProfile.HEARING_AID, false)
- ? MediaRoute2Info.TYPE_HEARING_AID : MediaRoute2Info.TYPE_BLUETOOTH_A2DP);
+ builder.setType(btRoute.getRouteType());
if (state == MediaRoute2Info.CONNECTION_STATE_CONNECTED) {
- int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
- int currentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
- builder.setVolumeMax(maxVolume).setVolume(currentVolume);
+ builder.setVolume(mVolumeMap.get(btRoute.getRouteType(), 0));
}
btRoute.route = builder.build();
}
@@ -254,6 +293,15 @@
public BluetoothDevice btDevice;
public MediaRoute2Info route;
public SparseBooleanArray connectedProfiles;
+
+ @MediaRoute2Info.Type
+ int getRouteType() {
+ // Let hearing aid profile have a priority.
+ if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
+ return MediaRoute2Info.TYPE_HEARING_AID;
+ }
+ return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ }
}
// These callbacks run on the main thread.
@@ -285,8 +333,6 @@
setRouteConnectionState(mSelectedRoute,
MediaRoute2Info.CONNECTION_STATE_CONNECTED);
}
-
- btRoute.connectedProfiles.put(profile, true);
}
notifyBluetoothRoutesUpdated();
}
@@ -344,15 +390,10 @@
BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress());
if (bondState == BluetoothDevice.BOND_BONDED && btRoute == null) {
btRoute = createBluetoothRoute(device);
- if (mA2dpProfile != null && mA2dpProfile.getConnectedDevices().contains(device)) {
- btRoute.connectedProfiles.put(BluetoothProfile.A2DP, true);
+ if (btRoute.connectedProfiles.size() > 0) {
+ mBluetoothRoutes.put(device.getAddress(), btRoute);
+ notifyBluetoothRoutesUpdated();
}
- if (mHearingAidProfile != null
- && mHearingAidProfile.getConnectedDevices().contains(device)) {
- btRoute.connectedProfiles.put(BluetoothProfile.HEARING_AID, true);
- }
- mBluetoothRoutes.put(device.getAddress(), btRoute);
- notifyBluetoothRoutesUpdated();
} else if (bondState == BluetoothDevice.BOND_NONE
&& mBluetoothRoutes.remove(device.getAddress()) != null) {
notifyBluetoothRoutesUpdated();
@@ -393,9 +434,10 @@
if (state == BluetoothProfile.STATE_CONNECTED) {
if (btRoute == null) {
btRoute = createBluetoothRoute(device);
- mBluetoothRoutes.put(device.getAddress(), btRoute);
- btRoute.connectedProfiles.put(profile, true);
- notifyBluetoothRoutesUpdated();
+ if (btRoute.connectedProfiles.size() > 0) {
+ mBluetoothRoutes.put(device.getAddress(), btRoute);
+ notifyBluetoothRoutesUpdated();
+ }
} else {
btRoute.connectedProfiles.put(profile, true);
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index a5de90c..a435f1e 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -315,9 +315,7 @@
return;
}
- sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
- .setProviderId(getUniqueId())
- .build();
+ sessionInfo = updateSessionInfo(sessionInfo);
boolean duplicateSessionAlreadyExists = false;
synchronized (mLock) {
@@ -348,9 +346,7 @@
return;
}
- sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
- .setProviderId(getUniqueId())
- .build();
+ sessionInfo = updateSessionInfo(sessionInfo);
boolean found = false;
synchronized (mLock) {
@@ -380,9 +376,7 @@
return;
}
- sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
- .setProviderId(getUniqueId())
- .build();
+ sessionInfo = updateSessionInfo(sessionInfo);
boolean found = false;
synchronized (mLock) {
@@ -403,6 +397,13 @@
mCallback.onSessionReleased(this, sessionInfo);
}
+ private RoutingSessionInfo updateSessionInfo(RoutingSessionInfo sessionInfo) {
+ return new RoutingSessionInfo.Builder(sessionInfo)
+ .setOwnerPackageName(mComponentName.getPackageName())
+ .setProviderId(getUniqueId())
+ .build();
+ }
+
private void onRequestFailed(Connection connection, long requestId, int reason) {
if (mActiveConnection != connection) {
return;
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 5e865e7..d7bd794 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -584,7 +584,8 @@
mAllRouterRecords.put(binder, routerRecord);
userRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::notifyRoutesToRouter, userRecord.mHandler, router));
+ obtainMessage(UserHandler::notifyRoutesToRouter,
+ userRecord.mHandler, routerRecord));
}
private void unregisterRouter2Locked(@NonNull IMediaRouter2 router, boolean died) {
@@ -1775,16 +1776,36 @@
}
}
- private void notifyRoutesToRouter(@NonNull IMediaRouter2 router) {
+ private void notifyRoutesToRouter(@NonNull RouterRecord routerRecord) {
List<MediaRoute2Info> routes = new ArrayList<>();
+
+ MediaRoute2ProviderInfo systemProviderInfo = null;
for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
+ // TODO: Create MediaRoute2ProviderInfo#isSystemProvider()
+ if (TextUtils.equals(providerInfo.getUniqueId(), mSystemProvider.getUniqueId())) {
+ // Adding routes from system provider will be handled below, so skip it here.
+ systemProviderInfo = providerInfo;
+ continue;
+ }
routes.addAll(providerInfo.getRoutes());
}
+
+ if (routerRecord.mHasModifyAudioRoutingPermission) {
+ if (systemProviderInfo != null) {
+ routes.addAll(systemProviderInfo.getRoutes());
+ } else {
+ // This shouldn't happen.
+ Slog.w(TAG, "notifyRoutesToRouter: System route provider not found.");
+ }
+ } else {
+ routes.add(mSystemProvider.getDefaultRoute());
+ }
+
if (routes.size() == 0) {
return;
}
try {
- router.notifyRoutesAdded(routes);
+ routerRecord.mRouter.notifyRoutesAdded(routes);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify all routes. Router probably died.", ex);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index bc0e816..84ec440 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1134,8 +1134,19 @@
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
- return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag,
- sessionInfo).getSessionBinder();
+ MediaSessionRecord session = createSessionInternal(
+ pid, uid, resolvedUserId, packageName, cb, tag, sessionInfo);
+ if (session == null) {
+ throw new IllegalStateException("Failed to create a new session record");
+ }
+ ISession sessionBinder = session.getSessionBinder();
+ if (sessionBinder == null) {
+ throw new IllegalStateException("Invalid session record");
+ }
+ return sessionBinder;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception in creating a new session", e);
+ throw e;
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index b585b49..fdee9f8 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -81,6 +81,7 @@
MediaRoute2Info mDeviceRoute;
RoutingSessionInfo mDefaultSessionInfo;
final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
+ int mDeviceVolume;
private final Object mRequestLock = new Object();
@GuardedBy("mRequestLock")
@@ -127,8 +128,9 @@
});
updateSessionInfosIfNeeded();
- mContext.registerReceiver(new VolumeChangeReceiver(),
- new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
+ IntentFilter intentFilter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
+ intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
+ mContext.registerReceiver(new AudioManagerBroadcastReceiver(), intentFilter);
if (mBtRouteProvider != null) {
mHandler.post(() -> {
@@ -136,6 +138,7 @@
notifyProviderState();
});
}
+ updateVolume();
}
@Override
@@ -248,8 +251,8 @@
.setVolumeHandling(mAudioManager.isVolumeFixed()
? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolume(mDeviceVolume)
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
- .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
.setType(type)
.addFeature(FEATURE_LIVE_AUDIO)
.addFeature(FEATURE_LIVE_VIDEO)
@@ -361,36 +364,43 @@
}
}
- private class VolumeChangeReceiver extends BroadcastReceiver {
+ void updateVolume() {
+ int devices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
+ int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+
+ if (mDefaultRoute.getVolume() != volume) {
+ mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute)
+ .setVolume(volume)
+ .build();
+ }
+
+ if (mBtRouteProvider != null && mBtRouteProvider.updateVolumeForDevices(devices, volume)) {
+ return;
+ }
+ if (mDeviceVolume != volume) {
+ mDeviceVolume = volume;
+ mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute)
+ .setVolume(volume)
+ .build();
+ }
+ publishProviderState();
+ }
+
+ private class AudioManagerBroadcastReceiver extends BroadcastReceiver {
// This will be called in the main thread.
@Override
public void onReceive(Context context, Intent intent) {
- if (!intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) {
+ if (!intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)
+ && !intent.getAction().equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
return;
}
- final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+ int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
if (streamType != AudioManager.STREAM_MUSIC) {
return;
}
- final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0);
- final int oldVolume = intent.getIntExtra(
- AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0);
-
- if (newVolume != oldVolume) {
- if (TextUtils.equals(mDeviceRoute.getId(), mSelectedRouteId)) {
- mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute)
- .setVolume(newVolume)
- .build();
- } else if (mBtRouteProvider != null) {
- mBtRouteProvider.setSelectedRouteVolume(newVolume);
- }
- mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute)
- .setVolume(newVolume)
- .build();
- publishProviderState();
- }
+ updateVolume();
}
}
}
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 9e509f4..1a749b3 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -22,6 +22,7 @@
import android.app.IProcessObserver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
@@ -43,6 +44,7 @@
import android.util.ArrayMap;
import android.util.Slog;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -399,11 +401,12 @@
public final UserHandle userHandle;
private final int mTargetSdkVersion;
private final boolean mIsPrivileged;
+ private final int mType;
private IMediaProjectionCallback mCallback;
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
- private int mType;
+ private boolean mRestoreSystemAlertWindow;
MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
boolean isPrivileged) {
@@ -494,6 +497,35 @@
"MediaProjectionCallbacks must be valid, aborting MediaProjection", e);
return;
}
+ if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // We allow an app running a current screen capture session to use
+ // SYSTEM_ALERT_WINDOW for the duration of the session, to enable
+ // them to overlay their UX on top of what is being captured.
+ // We only do this if the app requests the permission, and the appop
+ // is in its default state (the user has neither explicitly allowed nor
+ // disallowed it).
+ final PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(
+ packageName, PackageManager.GET_PERMISSIONS,
+ UserHandle.getUserId(uid));
+ if (ArrayUtils.contains(packageInfo.requestedPermissions,
+ Manifest.permission.SYSTEM_ALERT_WINDOW)) {
+ final int currentMode = mAppOps.unsafeCheckOpRawNoThrow(
+ AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);
+ if (currentMode == AppOpsManager.MODE_DEFAULT) {
+ mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid,
+ packageName, AppOpsManager.MODE_ALLOWED);
+ mRestoreSystemAlertWindow = true;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Package not found, aborting MediaProjection", e);
+ return;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
startProjectionLocked(this);
}
}
@@ -507,6 +539,24 @@
+ "pid=" + Binder.getCallingPid() + ")");
return;
}
+ if (mRestoreSystemAlertWindow) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Put the appop back how it was, unless it has been changed from what
+ // we set it to.
+ // Note that WindowManager takes care of removing any existing overlay
+ // windows when we do this.
+ final int currentMode = mAppOps.unsafeCheckOpRawNoThrow(
+ AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);
+ if (currentMode == AppOpsManager.MODE_ALLOWED) {
+ mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName,
+ AppOpsManager.MODE_DEFAULT);
+ }
+ mRestoreSystemAlertWindow = false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
stopProjectionLocked(this);
mToken.unlinkToDeath(mDeathEater, 0);
mToken = null;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ec941c8..3283fd9b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -799,7 +799,6 @@
writePolicyAL();
}
- enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true);
setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service");
updateRulesForGlobalChangeAL(false);
updateNotificationsNL();
@@ -871,6 +870,9 @@
new NetworkRequest.Builder().build(), mNetworkCallback);
mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener());
+ synchronized (mUidRulesFirstLock) {
+ updateRulesForAppIdleParoleUL();
+ }
// Listen for subscriber changes
mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
@@ -3893,6 +3895,39 @@
}
/**
+ * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
+ * changed.
+ */
+ @GuardedBy("mUidRulesFirstLock")
+ private void updateRulesForAppIdleParoleUL() {
+ final boolean paroled = mAppStandby.isInParole();
+ final boolean enableChain = !paroled;
+ enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
+
+ int ruleCount = mUidFirewallStandbyRules.size();
+ for (int i = 0; i < ruleCount; i++) {
+ final int uid = mUidFirewallStandbyRules.keyAt(i);
+ int oldRules = mUidRules.get(uid);
+ if (enableChain) {
+ // Chain wasn't enabled before and the other power-related
+ // chains are whitelists, so we can clear the
+ // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
+ // the effective rules result in blocking network access.
+ oldRules &= MASK_METERED_NETWORKS;
+ } else {
+ // Skip if it had no restrictions to begin with
+ if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
+ }
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ if (newUidRules == RULE_NONE) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, newUidRules);
+ }
+ }
+ }
+
+ /**
* Update rules that might be changed by {@link #mRestrictBackground},
* {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
*/
@@ -4347,7 +4382,7 @@
private void updateRulesForPowerRestrictionsUL(int uid) {
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules);
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
@@ -4361,28 +4396,30 @@
*
* @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change
+ * @param paroled whether to ignore idle state of apps and only look at other restrictions
*
* @return the new computed rules for the uid
*/
- private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules) {
+ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
- "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules);
+ "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
+ + (paroled ? "P" : "-"));
}
try {
- return updateRulesForPowerRestrictionsULInner(uid, oldUidRules);
+ return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
- private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules) {
+ private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) {
if (!isUidValidForBlacklistRules(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return RULE_NONE;
}
- final boolean isIdle = isUidIdle(uid);
+ final boolean isIdle = !paroled && isUidIdle(uid);
final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
@@ -4452,6 +4489,14 @@
} catch (NameNotFoundException nnfe) {
}
}
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ synchronized (mUidRulesFirstLock) {
+ mLogger.paroleStateChanged(isParoleOn);
+ updateRulesForAppIdleParoleUL();
+ }
+ }
}
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 1951fc0..dcbdfdf 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -119,7 +119,6 @@
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -160,6 +159,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -178,6 +178,9 @@
// Perform polling, persist network, and register the global alert again.
private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
private static final int MSG_UPDATE_IFACES = 3;
+ // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent
+ // deadlock.
+ private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4;
/** Flags to control detail level of poll event. */
private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -224,12 +227,6 @@
private static final String PREFIX_UID_TAG = "uid_tag";
/**
- * Virtual network interface for video telephony. This is for VT data usage counting purpose.
- */
- // TODO: Remove this after no one is using it.
- public static final String VT_INTERFACE = NetworkStats.IFACE_VT;
-
- /**
* Settings that can be changed externally.
*/
public interface NetworkStatsSettings {
@@ -301,8 +298,8 @@
new DropBoxNonMonotonicObserver();
private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100;
- private final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList =
- new RemoteCallbackList<>();
+ private final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList =
+ new CopyOnWriteArrayList<>();
/** Semaphore used to wait for stats provider to respond to request stats update. */
private final Semaphore mStatsProviderSem = new Semaphore(0, true);
@@ -386,6 +383,13 @@
registerGlobalAlert();
break;
}
+ case MSG_BROADCAST_NETWORK_STATS_UPDATED: {
+ final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
+ updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
+ READ_NETWORK_USAGE_HISTORY);
+ break;
+ }
}
}
}
@@ -1456,10 +1460,14 @@
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
// Request asynchronous stats update from all providers for next poll. And wait a bit of
- // time to allow providers report-in given that normally binder call should be fast.
+ // time to allow providers report-in given that normally binder call should be fast. Note
+ // that size of list might be changed because addition/removing at the same time. For
+ // addition, the stats of the missed provider can only be collected in next poll;
+ // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS
+ // once that happened.
// TODO: request with a valid token.
Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate");
- final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount();
+ final int registeredCallbackCount = mStatsProviderCbList.size();
mStatsProviderSem.drainPermits();
invokeForAllStatsProviderCallbacks(
(cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */));
@@ -1513,10 +1521,7 @@
}
// finally, dispatch updated event to any listeners
- final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
- updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
- READ_NETWORK_USAGE_HISTORY);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
Trace.traceEnd(TRACE_TAG_NETWORK);
}
@@ -1636,7 +1641,7 @@
@Override
public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
- Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
+ if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota));
}
}
@@ -1927,7 +1932,7 @@
NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl(
tag, provider, mStatsProviderSem, mAlertObserver,
mStatsProviderCbList);
- mStatsProviderCbList.register(callback);
+ mStatsProviderCbList.add(callback);
Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid="
+ getCallingUid() + "/" + getCallingPid());
return callback;
@@ -1951,20 +1956,11 @@
private void invokeForAllStatsProviderCallbacks(
@NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) {
- synchronized (mStatsLock) {
- final int length = mStatsProviderCbList.beginBroadcast();
+ for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) {
try {
- for (int i = 0; i < length; i++) {
- final NetworkStatsProviderCallbackImpl cb =
- mStatsProviderCbList.getBroadcastItem(i);
- try {
- task.accept(cb);
- } catch (RemoteException e) {
- Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e);
- }
- }
- } finally {
- mStatsProviderCbList.finishBroadcast();
+ task.accept(cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e);
}
}
}
@@ -1976,7 +1972,7 @@
@NonNull final INetworkStatsProvider mProvider;
@NonNull private final Semaphore mSemaphore;
@NonNull final INetworkManagementEventObserver mAlertObserver;
- @NonNull final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList;
+ @NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList;
@NonNull private final Object mProviderStatsLock = new Object();
@@ -1990,7 +1986,7 @@
@NonNull String tag, @NonNull INetworkStatsProvider provider,
@NonNull Semaphore semaphore,
@NonNull INetworkManagementEventObserver alertObserver,
- @NonNull RemoteCallbackList<NetworkStatsProviderCallbackImpl> cbList)
+ @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList)
throws RemoteException {
mTag = tag;
mProvider = provider;
@@ -2047,13 +2043,13 @@
@Override
public void binderDied() {
Log.d(TAG, mTag + ": binderDied");
- mStatsProviderCbList.unregister(this);
+ mStatsProviderCbList.remove(this);
}
@Override
public void unregister() {
Log.d(TAG, mTag + ": unregister");
- mStatsProviderCbList.unregister(this);
+ mStatsProviderCbList.remove(this);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bc7bd23..86e8734 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2725,9 +2725,18 @@
Context appContext = r.getSbn().getPackageContext(getContext());
Notification.Builder nb =
Notification.Builder.recoverBuilder(appContext, r.getNotification());
- if (nb.getStyle() instanceof Notification.MessagingStyle && r.getShortcutInfo() == null) {
- mPreferencesHelper.setMessageSent(r.getSbn().getPackageName(), r.getUid());
- handleSavePolicyFile();
+ if (nb.getStyle() instanceof Notification.MessagingStyle) {
+ if (r.getShortcutInfo() != null) {
+ if (mPreferencesHelper.setValidMessageSent(
+ r.getSbn().getPackageName(), r.getUid())) {
+ handleSavePolicyFile();
+ }
+ } else {
+ if (mPreferencesHelper.setInvalidMessageSent(
+ r.getSbn().getPackageName(), r.getUid())) {
+ handleSavePolicyFile();
+ }
+ }
}
}
@@ -3158,9 +3167,22 @@
}
@Override
- public boolean hasSentMessage(String pkg, int uid) {
+ public boolean isInInvalidMsgState(String pkg, int uid) {
checkCallerIsSystem();
- return mPreferencesHelper.hasSentMessage(pkg, uid);
+ return mPreferencesHelper.isInInvalidMsgState(pkg, uid);
+ }
+
+ @Override
+ public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) {
+ checkCallerIsSystem();
+ return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid);
+ }
+
+ @Override
+ public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) {
+ checkCallerIsSystem();
+ mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted);
+ handleSavePolicyFile();
}
@Override
@@ -5698,6 +5720,9 @@
Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut");
}
r.setShortcutInfo(info);
+ r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid));
+ r.userDemotedAppFromConvoSpace(
+ mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
r.getSbn().getOverrideGroupKey() != null)) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 8e3de15..c107822 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -188,6 +188,8 @@
private boolean mHasSeenSmartReplies;
private boolean mFlagBubbleRemoved;
private boolean mPostSilently;
+ private boolean mHasSentValidMsg;
+ private boolean mAppDemotedFromConvo;
/**
* Whether this notification (and its channels) should be considered user locked. Used in
* conjunction with user sentiment calculation.
@@ -1377,18 +1379,40 @@
return mShortcutInfo;
}
+ public void setHasSentValidMsg(boolean hasSentValidMsg) {
+ mHasSentValidMsg = hasSentValidMsg;
+ }
+
+ public void userDemotedAppFromConvoSpace(boolean userDemoted) {
+ mAppDemotedFromConvo = userDemoted;
+ }
+
/**
* Whether this notification is a conversation notification.
*/
public boolean isConversation() {
Notification notification = getNotification();
- if (mChannel.isDemoted()
- || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
+ if (!Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
+ // very common; don't bother logging
+ return false;
+ }
+ if (mChannel.isDemoted()) {
return false;
}
if (mIsNotConversationOverride) {
return false;
}
+ if (mTargetSdkVersion >= Build.VERSION_CODES.R
+ && Notification.MessagingStyle.class.equals(notification.getNotificationStyle())
+ && mShortcutInfo == null) {
+ return false;
+ }
+ if (mHasSentValidMsg && mShortcutInfo == null) {
+ return false;
+ }
+ if (mAppDemotedFromConvo) {
+ return false;
+ }
return true;
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index c6ec95a..2b8ee92e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -62,7 +62,7 @@
/* android.stats.sysui.NotificationImportance importance_asst = 19 */
r.getAssistantImportance(),
/* int32 assistant_hash = 20 */ p.getAssistantHash(),
- /* float assistant_ranking_score = 21 */ 0 // TODO connect up ranking score
+ /* float assistant_ranking_score = 21 */ r.getRankingScore()
);
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index ec0fc4a..38c65f1 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -116,7 +116,9 @@
private static final String ATT_ENABLED = "enabled";
private static final String ATT_USER_ALLOWED = "allowed";
private static final String ATT_HIDE_SILENT = "hide_gentle";
- private static final String ATT_SENT_MESSAGE = "sent_invalid_msg";
+ private static final String ATT_SENT_INVALID_MESSAGE = "sent_invalid_msg";
+ private static final String ATT_SENT_VALID_MESSAGE = "sent_valid_msg";
+ private static final String ATT_USER_DEMOTED_INVALID_MSG_APP = "user_demote_msg_app";
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -253,8 +255,12 @@
parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
r.lockedAppFields = XmlUtils.readIntAttribute(parser,
ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
- r.hasSentMessage = XmlUtils.readBooleanAttribute(
- parser, ATT_SENT_MESSAGE, false);
+ r.hasSentInvalidMessage = XmlUtils.readBooleanAttribute(
+ parser, ATT_SENT_INVALID_MESSAGE, false);
+ r.hasSentValidMessage = XmlUtils.readBooleanAttribute(
+ parser, ATT_SENT_VALID_MESSAGE, false);
+ r.userDemotedMsgApp = XmlUtils.readBooleanAttribute(
+ parser, ATT_USER_DEMOTED_INVALID_MSG_APP, false);
final int innerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -497,7 +503,9 @@
|| r.groups.size() > 0
|| r.delegate != null
|| r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE
- || r.hasSentMessage;
+ || r.hasSentInvalidMessage
+ || r.userDemotedMsgApp
+ || r.hasSentValidMessage;
if (hasNonDefaultSettings) {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
@@ -516,7 +524,12 @@
out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
Integer.toString(r.lockedAppFields));
- out.attribute(null, ATT_SENT_MESSAGE, Boolean.toString(r.hasSentMessage));
+ out.attribute(null, ATT_SENT_INVALID_MESSAGE,
+ Boolean.toString(r.hasSentInvalidMessage));
+ out.attribute(null, ATT_SENT_VALID_MESSAGE,
+ Boolean.toString(r.hasSentValidMessage));
+ out.attribute(null, ATT_USER_DEMOTED_INVALID_MSG_APP,
+ Boolean.toString(r.userDemotedMsgApp));
if (!forBackup) {
out.attribute(null, ATT_UID, Integer.toString(r.uid));
@@ -635,15 +648,68 @@
updateConfig();
}
- public boolean hasSentMessage(String packageName, int uid) {
+ public boolean isInInvalidMsgState(String packageName, int uid) {
synchronized (mPackagePreferences) {
- return getOrCreatePackagePreferencesLocked(packageName, uid).hasSentMessage;
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ return r.hasSentInvalidMessage && !r.hasSentValidMessage;
}
}
- public void setMessageSent(String packageName, int uid) {
+ public boolean hasUserDemotedInvalidMsgApp(String packageName, int uid) {
synchronized (mPackagePreferences) {
- getOrCreatePackagePreferencesLocked(packageName, uid).hasSentMessage = true;
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ return isInInvalidMsgState(packageName, uid) ? r.userDemotedMsgApp : false;
+ }
+ }
+
+ public void setInvalidMsgAppDemoted(String packageName, int uid, boolean isDemoted) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ r.userDemotedMsgApp = isDemoted;
+ }
+ }
+
+ public boolean setInvalidMessageSent(String packageName, int uid) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ boolean valueChanged = r.hasSentInvalidMessage == false;
+ r.hasSentInvalidMessage = true;
+
+ return valueChanged;
+ }
+ }
+
+ public boolean setValidMessageSent(String packageName, int uid) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ boolean valueChanged = r.hasSentValidMessage == false;
+ r.hasSentValidMessage = true;
+
+ return valueChanged;
+ }
+ }
+
+ @VisibleForTesting
+ boolean hasSentInvalidMsg(String packageName, int uid) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ return r.hasSentInvalidMessage;
+ }
+ }
+
+ @VisibleForTesting
+ boolean hasSentValidMsg(String packageName, int uid) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ return r.hasSentValidMessage;
+ }
+ }
+
+ @VisibleForTesting
+ boolean didUserEverDemoteInvalidMsgApp(String packageName, int uid) {
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+ return r.userDemotedMsgApp;
}
}
@@ -2273,7 +2339,11 @@
boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
List<String> oemLockedChannels = new ArrayList<>();
boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
- boolean hasSentMessage = false;
+
+ boolean hasSentInvalidMessage = false;
+ boolean hasSentValidMessage = false;
+ // notE: only valid while hasSentMessage is false and hasSentInvalidMessage is true
+ boolean userDemotedMsgApp = false;
Delegate delegate = null;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index d862e4f..a490b9c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1369,7 +1369,7 @@
.setContentTitle(mContext.getResources().getString(title))
.setContentText(mContext.getResources().getString(content))
.setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
- PendingIntent.FLAG_UPDATE_CURRENT))
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
.setAutoCancel(true)
.setLocalOnly(true)
.addExtras(extras)
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index acce699..aafd261 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -30,9 +30,9 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Binder;
import android.os.Environment;
import android.os.RemoteException;
@@ -50,7 +50,6 @@
import com.android.internal.util.Preconditions;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.utils.TimingsTraceAndSlog;
import com.google.android.collect.Lists;
@@ -491,7 +490,7 @@
for (ApexInfo ai : allPkgs) {
File apexFile = new File(ai.modulePath);
- parallelPackageParser.submit(apexFile, 0);
+ parallelPackageParser.submit(apexFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
parsingApexInfo.put(apexFile, ai);
}
@@ -504,18 +503,8 @@
ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
if (throwable == null) {
- // Unfortunately, ParallelPackageParser won't collect certificates for us. We
- // need to manually collect them here.
- ParsedPackage pp = parseResult.parsedPackage;
- try {
- pp.setSigningDetails(
- ParsingPackageUtils.collectCertificates(pp, false));
- } catch (PackageParserException e) {
- throw new IllegalStateException(
- "Unable to collect certificates for " + ai.modulePath, e);
- }
final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
- pp, ai, flags);
+ parseResult.parsedPackage, ai, flags);
if (packageInfo == null) {
throw new IllegalStateException("Unable to generate package info: "
+ ai.modulePath);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 118fdcb..f9d805e 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -417,7 +417,7 @@
public void grantImplicitAccess(int recipientUid, int visibleUid) {
if (recipientUid != visibleUid
&& mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
- Slog.wtf(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+ Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
}
}
@@ -720,12 +720,12 @@
return false;
}
if (callingSetting == null) {
- Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
+ Slog.w(TAG, "No setting found for non system uid " + callingUid);
return true;
}
final PackageSetting callingPkgSetting;
final ArraySet<PackageSetting> callingSharedPkgSettings;
- Trace.beginSection("callingSetting instanceof");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof");
if (callingSetting instanceof PackageSetting) {
callingPkgSetting = (PackageSetting) callingSetting;
callingSharedPkgSettings = null;
@@ -733,7 +733,7 @@
callingPkgSetting = null;
callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages;
}
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (callingPkgSetting != null) {
if (callingPkgSetting.pkg != null
@@ -760,7 +760,7 @@
final AndroidPackage targetPkg = targetPkgSetting.pkg;
if (targetPkg == null) {
if (DEBUG_LOGGING) {
- Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
+ Slog.w(TAG, "shouldFilterApplication: " + "targetPkg is null");
}
return true;
}
@@ -769,7 +769,7 @@
return false;
}
final String targetName = targetPkg.getPackageName();
- Trace.beginSection("getAppId");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId");
final int callingAppId;
if (callingPkgSetting != null) {
callingAppId = callingPkgSetting.appId;
@@ -777,7 +777,7 @@
callingAppId = callingSharedPkgSettings.valueAt(0).appId; // all should be the same
}
final int targetAppId = targetPkgSetting.appId;
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (callingAppId == targetAppId) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "same app id");
@@ -786,7 +786,7 @@
}
try {
- Trace.beginSection("hasPermission");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission");
if (callingSetting.getPermissionsState().hasPermission(
Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) {
if (DEBUG_LOGGING) {
@@ -795,10 +795,10 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mForceQueryable");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
if (mForceQueryable.contains(targetAppId)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "force queryable");
@@ -806,10 +806,10 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mQueriesViaPackage");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaPackage");
if (mQueriesViaPackage.contains(callingAppId, targetAppId)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "queries package");
@@ -817,10 +817,10 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mQueriesViaComponent");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent");
if (mQueriesViaComponent.contains(callingAppId, targetAppId)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "queries component");
@@ -828,11 +828,11 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mImplicitlyQueryable");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
final int targetUid = UserHandle.getUid(userId, targetAppId);
if (mImplicitlyQueryable.contains(callingUid, targetUid)) {
if (DEBUG_LOGGING) {
@@ -841,11 +841,11 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mOverlayReferenceMapper");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
if (callingSharedPkgSettings != null) {
int size = callingSharedPkgSettings.size();
for (int index = 0; index < size; index++) {
@@ -868,7 +868,7 @@
}
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 28c8642d..e82ee22 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -50,6 +50,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
import android.util.Slog;
@@ -458,6 +459,10 @@
+ packageName + " on user ID " + userId);
return;
}
+
+ final boolean hadPermission = hasInteractAcrossProfilesPermission(
+ packageName, uid, PermissionChecker.PID_UNKNOWN);
+
final int callingUid = mInjector.getCallingUid();
if (isPermissionGranted(
Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, callingUid)) {
@@ -472,6 +477,22 @@
}
sendCanInteractAcrossProfilesChangedBroadcast(packageName, uid, UserHandle.of(userId));
maybeLogSetInteractAcrossProfilesAppOp(packageName, newMode, userId, logMetrics, uid);
+ maybeKillUid(packageName, uid, hadPermission);
+ }
+
+ /**
+ * Kills the process represented by the given UID if it has lost the permission to
+ * interact across profiles.
+ */
+ private void maybeKillUid(
+ String packageName, int uid, boolean hadPermission) {
+ if (!hadPermission) {
+ return;
+ }
+ if (hasInteractAcrossProfilesPermission(packageName, uid, PermissionChecker.PID_UNKNOWN)) {
+ return;
+ }
+ mInjector.killUid(packageName, uid);
}
private void maybeLogSetInteractAcrossProfilesAppOp(
@@ -774,6 +795,18 @@
String permission, int uid, int owningUid, boolean exported) {
return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
}
+
+ @Override
+ public void killUid(String packageName, int uid) {
+ try {
+ ActivityManager.getService().killApplication(
+ packageName,
+ UserHandle.getAppId(uid),
+ UserHandle.getUserId(uid),
+ PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED);
+ } catch (RemoteException ignored) {
+ }
+ }
}
@VisibleForTesting
@@ -813,6 +846,8 @@
void sendBroadcastAsUser(Intent intent, UserHandle user);
int checkComponentPermission(String permission, int uid, int owningUid, boolean exported);
+
+ void killUid(String packageName, int uid);
}
class LocalService extends CrossProfileAppsInternal {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 3367cd5..236a681 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -676,7 +676,7 @@
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
installSource, params, createdMillis,
- stageDir, stageCid, null, false, false, false, null, SessionInfo.INVALID_ID,
+ stageDir, stageCid, null, false, false, false, false, null, SessionInfo.INVALID_ID,
false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
synchronized (mSessions) {
@@ -830,7 +830,7 @@
synchronized (mSessions) {
final PackageInstallerSession session = mSessions.get(sessionId);
- return session != null
+ return (session != null && !(session.isStaged() && session.isDestroyed()))
? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid())
: null;
}
@@ -851,7 +851,8 @@
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.userId == userId && !session.hasParentSessionId()) {
+ if (session.userId == userId && !session.hasParentSessionId()
+ && !(session.isStaged() && session.isDestroyed())) {
result.add(session.generateInfoForCaller(false, callingUid));
}
}
@@ -933,6 +934,21 @@
}
@Override
+ public void uninstallExistingPackage(VersionedPackage versionedPackage,
+ String callerPackageName, IntentSender statusReceiver, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
+ mAppOps.checkPackage(callingUid, callerPackageName);
+ }
+
+ final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
+ statusReceiver, versionedPackage.getPackageName(), false, userId);
+ mPm.deleteExistingPackageAsUser(versionedPackage, adapter.getBinder(), userId);
+ }
+
+ @Override
public void installExistingPackage(String packageName, int installFlags, int installReason,
IntentSender statusReceiver, int userId, List<String> whiteListedPermissions) {
mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
@@ -1269,7 +1285,7 @@
public void onStagedSessionChanged(PackageInstallerSession session) {
session.markUpdated();
writeSessionsAsync();
- if (mOkToSendBroadcasts) {
+ if (mOkToSendBroadcasts && !session.isDestroyed()) {
// we don't scrub the data here as this is sent only to the installer several
// privileged system packages
mPm.sendSessionUpdatedBroadcast(
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3df044f..1741aa7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -86,6 +86,8 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Binder;
@@ -188,6 +190,7 @@
private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
private static final String ATTR_PREPARED = "prepared";
private static final String ATTR_COMMITTED = "committed";
+ private static final String ATTR_DESTROYED = "destroyed";
private static final String ATTR_SEALED = "sealed";
private static final String ATTR_MULTI_PACKAGE = "multiPackage";
private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
@@ -392,7 +395,6 @@
private boolean mDataLoaderFinished = false;
- // TODO(b/146080380): merge file list with Callback installation.
private IncrementalFileStorages mIncrementalFileStorages;
private static final FileFilter sAddedApkFilter = new FileFilter() {
@@ -531,7 +533,7 @@
int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
SessionParams params, long createdMillis,
File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
- boolean committed, boolean sealed,
+ boolean committed, boolean destroyed, boolean sealed,
@Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
String stagedSessionErrorMessage) {
@@ -577,6 +579,7 @@
mPrepared = prepared;
mCommitted = committed;
+ mDestroyed = destroyed;
mStagedSessionReady = isReady;
mStagedSessionFailed = isFailed;
mStagedSessionApplied = isApplied;
@@ -711,6 +714,13 @@
}
}
+ /** {@hide} */
+ boolean isDestroyed() {
+ synchronized (mLock) {
+ return mDestroyed;
+ }
+ }
+
/** Returns true if a staged session has reached a final state and can be forgotten about */
public boolean isStagedAndInTerminalState() {
synchronized (mLock) {
@@ -1066,6 +1076,19 @@
}
/**
+ * Check if the caller is the owner of this session. Otherwise throw a
+ * {@link SecurityException}.
+ */
+ @GuardedBy("mLock")
+ private void assertCallerIsOwnerOrRootOrSystemLocked() {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
+ && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("Session does not belong to uid " + callingUid);
+ }
+ }
+
+ /**
* If anybody is reading or writing data of the session, throw an {@link SecurityException}.
*/
@GuardedBy("mLock")
@@ -1144,9 +1167,7 @@
// as appropriate once all children have been processed
try {
PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
- if (!session.streamValidateAndCommit()) {
- allSessionsReady = false;
- }
+ allSessionsReady &= session.streamValidateAndCommit();
nonFailingSessions.add(session);
} catch (PackageManagerException e) {
allSessionsReady = false;
@@ -1155,10 +1176,14 @@
}
}
}
- // If we encountered any unrecoverable failures, destroy all
- // other impacted sessions besides the parent; that will be cleaned up by the
- // ChildStatusIntentReceiver.
+ // If we encountered any unrecoverable failures, destroy all other sessions including
+ // the parent
if (unrecoverableFailure != null) {
+ // {@link #streamValidateAndCommit()} calls
+ // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
+ // expect it to ever do so for parent sessions. Call that on this parent to clean
+ // it up and notify listeners of the error.
+ onSessionVerificationFailure(unrecoverableFailure);
// fail other child sessions that did not already fail
for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
PackageInstallerSession session = nonFailingSessions.get(i);
@@ -1225,6 +1250,15 @@
public void statusUpdate(Intent intent) {
mHandler.post(() -> {
if (mChildSessionsRemaining.size() == 0) {
+ // no children to deal with, ignore.
+ return;
+ }
+ final boolean destroyed;
+ synchronized (mLock) {
+ destroyed = mDestroyed;
+ }
+ if (destroyed) {
+ // the parent has already been terminated, ignore.
return;
}
final int sessionId = intent.getIntExtra(
@@ -1251,8 +1285,10 @@
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
PackageInstallerSession.this.sessionId);
mChildSessionsRemaining.clear(); // we're done. Don't send any more.
- onSessionVerificationFailure(status,
- intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
+ try {
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
}
});
}
@@ -1365,6 +1401,9 @@
* @throws PackageManagerException on an unrecoverable error.
*/
private boolean streamValidateAndCommit() throws PackageManagerException {
+ // TODO(patb): since the work done here for a parent session in a multi-package install is
+ // mostly superficial, consider splitting this method for the parent and
+ // single / child sessions.
synchronized (mLock) {
if (mCommitted) {
return true;
@@ -2016,15 +2055,16 @@
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (File addedFile : addedFiles) {
- final ApkLite apk;
- try {
- apk = ApkLiteParseUtils.parseApkLite(
- addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ if (result.isError()) {
+ throw new PackageManagerException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
}
+ final ApkLite apk = result.getResult();
if (!stagedSplits.add(apk.splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split " + apk.splitName + " was defined multiple times");
@@ -2113,16 +2153,22 @@
}
} else {
- final PackageLite existing;
- final ApkLite existingBase;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
- try {
- existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
- existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
- PackageParser.PARSE_COLLECT_CERTIFICATES);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
+ input.reset(), new File(appInfo.getCodePath()), 0);
+ if (pkgLiteResult.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
}
+ final PackageLite existing = pkgLiteResult.getResult();
+ ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
+ new File(appInfo.getBaseCodePath()),
+ PackageParser.PARSE_COLLECT_CERTIFICATES);
+ if (apkLiteResult.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ apkLiteResult.getErrorMessage(), apkLiteResult.getException());
+ }
+ final ApkLite existingBase = apkLiteResult.getResult();
assertApkConsistentLocked("Existing base", existingBase);
@@ -2543,7 +2589,13 @@
+ mParentSessionId + " and may not be abandoned directly.");
}
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ if (params.isStaged && mDestroyed) {
+ // If a user abandons staged session in an unsafe state, then system will try to
+ // abandon the destroyed staged session when it is safe on behalf of the user.
+ assertCallerIsOwnerOrRootOrSystemLocked();
+ } else {
+ assertCallerIsOwnerOrRootLocked();
+ }
if (isStagedAndInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
@@ -2553,11 +2605,12 @@
return;
}
if (mCommitted && params.isStaged) {
- synchronized (mLock) {
- mDestroyed = true;
+ mDestroyed = true;
+ if (!mStagingManager.abortCommittedSessionLocked(this)) {
+ // Do not clean up the staged session from system. It is not safe yet.
+ mCallback.onStagedSessionChanged(this);
+ return;
}
- mStagingManager.abortCommittedSession(this);
-
cleanStageDir();
}
@@ -2644,6 +2697,7 @@
/**
* Makes sure files are present in staging location.
+ * @return if the image is ready for installation
*/
@GuardedBy("mLock")
private boolean prepareDataLoaderLocked()
@@ -2655,6 +2709,17 @@
return true;
}
+ // Retrying commit.
+ if (mIncrementalFileStorages != null) {
+ try {
+ mIncrementalFileStorages.startLoading();
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
+ e.getCause());
+ }
+ return false;
+ }
+
final List<InstallationFileParcel> addedFiles = new ArrayList<>();
final List<String> removedFiles = new ArrayList<>();
@@ -2917,6 +2982,7 @@
/** {@hide} */
void setStagedSessionReady() {
synchronized (mLock) {
+ if (mDestroyed) return; // Do not allow destroyed staged session to change state
mStagedSessionReady = true;
mStagedSessionApplied = false;
mStagedSessionFailed = false;
@@ -2930,6 +2996,7 @@
void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
String errorMessage) {
synchronized (mLock) {
+ if (mDestroyed) return; // Do not allow destroyed staged session to change state
mStagedSessionReady = false;
mStagedSessionApplied = false;
mStagedSessionFailed = true;
@@ -2944,6 +3011,7 @@
/** {@hide} */
void setStagedSessionApplied() {
synchronized (mLock) {
+ if (mDestroyed) return; // Do not allow destroyed staged session to change state
mStagedSessionReady = false;
mStagedSessionApplied = true;
mStagedSessionFailed = false;
@@ -3188,7 +3256,7 @@
*/
void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
synchronized (mLock) {
- if (mDestroyed) {
+ if (mDestroyed && !params.isStaged) {
return;
}
@@ -3214,6 +3282,7 @@
}
writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
+ writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed());
writeBooleanAttribute(out, ATTR_SEALED, isSealed());
writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
@@ -3343,6 +3412,7 @@
final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
+ final boolean destroyed = readBooleanAttribute(in, ATTR_DESTROYED);
final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
SessionInfo.INVALID_ID);
@@ -3464,7 +3534,7 @@
return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, stagingManager, sessionId, userId, installerUid,
installSource, params, createdMillis, stageDir, stageCid, fileArray,
- prepared, committed, sealed, childSessionIdsArray, parentSessionId,
+ prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4a26587..3e587bf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -223,6 +223,7 @@
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
+import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -232,6 +233,8 @@
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -605,6 +608,12 @@
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
+ * The default maximum time to wait for the integrity verification to return in
+ * milliseconds.
+ */
+ private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
+
+ /**
* Timeout duration in milliseconds for enabling package rollback. If we fail to enable
* rollback within that period, the install will proceed without rollback enabled.
*
@@ -1557,13 +1566,17 @@
// Recordkeeping of restore-after-install operations that are currently in flight
// between the Package Manager and the Backup Manager
static class PostInstallData {
+ @Nullable
public final InstallArgs args;
+ @NonNull
public final PackageInstalledInfo res;
+ @Nullable
public final Runnable mPostInstallRunnable;
- PostInstallData(InstallArgs _a, PackageInstalledInfo _r, Runnable postInstallRunnable) {
- args = _a;
- res = _r;
+ PostInstallData(@Nullable InstallArgs args, @NonNull PackageInstalledInfo res,
+ @Nullable Runnable postInstallRunnable) {
+ this.args = args;
+ this.res = res;
mPostInstallRunnable = postInstallRunnable;
}
}
@@ -1705,7 +1718,7 @@
if (data != null && data.mPostInstallRunnable != null) {
data.mPostInstallRunnable.run();
- } else if (data != null) {
+ } else if (data != null && data.args != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
@@ -1723,26 +1736,12 @@
: args.whitelistedRestrictedPermissions;
int autoRevokePermissionsMode = args.autoRevokePermissionsMode;
- // Handle the parent package
handlePackagePostInstall(parentRes, grantPermissions,
killApp, virtualPreload, grantedPermissions,
whitelistedRestrictedPermissions, autoRevokePermissionsMode,
didRestore, args.installSource.installerPackageName, args.observer,
args.mDataLoaderType);
- // Handle the child packages
- final int childCount = (parentRes.addedChildPackages != null)
- ? parentRes.addedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
- handlePackagePostInstall(childRes, grantPermissions,
- killApp, virtualPreload, grantedPermissions,
- whitelistedRestrictedPermissions, autoRevokePermissionsMode,
- false /*didRestore*/,
- args.installSource.installerPackageName, args.observer,
- args.mDataLoaderType);
- }
-
// Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
@@ -2297,27 +2296,8 @@
// Work that needs to happen on first install within each user
if (firstUserIds != null && firstUserIds.length > 0) {
for (int userId : firstUserIds) {
- // If this app is a browser and it's newly-installed for some
- // users, clear any default-browser state in those users. The
- // app's nature doesn't depend on the user, so we can just check
- // its browser nature in any user and generalize.
- if (packageIsBrowser(packageName, userId)) {
- // If this browser is restored from user's backup, do not clear
- // default-browser state for this user
- if (pkgSetting.getInstallReason(userId)
- != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
- mPermissionManager.setDefaultBrowser(null, true, true, userId);
- }
- }
-
- // We may also need to apply pending (restored) runtime permission grants
- // within these users.
- mPermissionManager.restoreDelayedRuntimePermissions(packageName,
- UserHandle.of(userId));
-
- // Persistent preferred activity might have came into effect due to this
- // install.
- updateDefaultHomeNotLocked(userId);
+ clearRolesAndRestorePermissionsForNewUserInstall(packageName,
+ pkgSetting.getInstallReason(userId), userId);
}
}
@@ -4426,11 +4406,6 @@
if (getInstantAppPackageName(callingUid) != null) {
throw new SecurityException("Instant applications don't have access to this method");
}
- if (!mUserManager.exists(userId)) {
- throw new SecurityException("User doesn't exist");
- }
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, false, false, "checkPackageStartable");
final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -5803,15 +5778,9 @@
@Override
public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
+ if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
- if (!mUserManager.exists(userId)) {
- return null;
- }
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, false, false, "getChangedPackages");
synchronized (mLock) {
if (sequenceNumber >= mChangedPackagesSequenceNumber) {
return null;
@@ -5974,25 +5943,7 @@
|| shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- SigningDetails p1SigningDetails = p1.getSigningDetails();
- SigningDetails p2SigningDetails = p2.getSigningDetails();
- int result = compareSignatures(p1SigningDetails.signatures,
- p2SigningDetails.signatures);
- // To support backwards compatibility with clients of this API expecting pre-key
- // rotation results if either of the packages has a signing lineage the oldest signer
- // in the lineage is used for signature verification.
- if (result != PackageManager.SIGNATURE_MATCH && (
- p1SigningDetails.hasPastSigningCertificates()
- || p2SigningDetails.hasPastSigningCertificates())) {
- Signature[] p1Signatures = p1SigningDetails.hasPastSigningCertificates()
- ? new Signature[]{p1SigningDetails.pastSigningCertificates[0]}
- : p1SigningDetails.signatures;
- Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates()
- ? new Signature[]{p2SigningDetails.pastSigningCertificates[0]}
- : p2SigningDetails.signatures;
- result = compareSignatures(p1Signatures, p2Signatures);
- }
- return result;
+ return checkSignaturesInternal(p1.getSigningDetails(), p2.getSigningDetails());
}
}
@@ -6006,21 +5957,21 @@
final int appId2 = UserHandle.getAppId(uid2);
// reader
synchronized (mLock) {
- Signature[] s1;
- Signature[] s2;
+ SigningDetails p1SigningDetails;
+ SigningDetails p2SigningDetails;
Object obj = mSettings.getSettingLPr(appId1);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
+ p1SigningDetails = ((SharedUserSetting) obj).signatures.mSigningDetails;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s1 = ps.signatures.mSigningDetails.signatures;
+ p1SigningDetails = ps.signatures.mSigningDetails;
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
@@ -6033,23 +5984,53 @@
if (isCallerInstantApp) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
+ p2SigningDetails = ((SharedUserSetting) obj).signatures.mSigningDetails;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s2 = ps.signatures.mSigningDetails.signatures;
+ p2SigningDetails = ps.signatures.mSigningDetails;
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return compareSignatures(s1, s2);
+ return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
}
}
+ private int checkSignaturesInternal(SigningDetails p1SigningDetails,
+ SigningDetails p2SigningDetails) {
+ if (p1SigningDetails == null) {
+ return p2SigningDetails == null
+ ? PackageManager.SIGNATURE_NEITHER_SIGNED
+ : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
+ }
+ if (p2SigningDetails == null) {
+ return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
+ }
+ int result = compareSignatures(p1SigningDetails.signatures, p2SigningDetails.signatures);
+ if (result == PackageManager.SIGNATURE_MATCH) {
+ return result;
+ }
+ // To support backwards compatibility with clients of this API expecting pre-key
+ // rotation results if either of the packages has a signing lineage the oldest signer
+ // in the lineage is used for signature verification.
+ if (p1SigningDetails.hasPastSigningCertificates()
+ || p2SigningDetails.hasPastSigningCertificates()) {
+ Signature[] p1Signatures = p1SigningDetails.hasPastSigningCertificates()
+ ? new Signature[]{p1SigningDetails.pastSigningCertificates[0]}
+ : p1SigningDetails.signatures;
+ Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates()
+ ? new Signature[]{p2SigningDetails.pastSigningCertificates[0]}
+ : p2SigningDetails.signatures;
+ result = compareSignatures(p1Signatures, p2Signatures);
+ }
+ return result;
+ }
+
@Override
public boolean hasSigningCertificate(
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
@@ -7200,11 +7181,14 @@
sortResult = true;
}
} else {
- final AndroidPackage pkg = mPackages.get(pkgName);
+ final PackageSetting setting =
+ getPackageSettingInternal(pkgName, Process.SYSTEM_UID);
result = null;
- if (pkg != null) {
+ if (setting != null && setting.pkg != null
+ && !shouldFilterApplicationLocked(setting, filterCallingUid, userId)) {
result = filterIfNotSystemUser(mComponentResolver.queryActivities(
- intent, resolvedType, flags, pkg.getActivities(), userId), userId);
+ intent, resolvedType, flags, setting.pkg.getActivities(), userId),
+ userId);
}
if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
@@ -8816,10 +8800,8 @@
private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, false, false, "resolveContentProvider");
flags = updateFlagsForComponent(flags, userId);
+ final int callingUid = Binder.getCallingUid();
final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
if (providerInfo == null) {
return null;
@@ -9070,7 +9052,7 @@
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
parsedPackage.setSigningDetails(
- ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
+ ParsingPackageUtils.getSigningDetails(parsedPackage, skipVerify));
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -13114,9 +13096,15 @@
createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
res.pkg = pkgSetting.pkg;
res.newUsers = new int[]{ userId };
- PostInstallData postInstallData = intentSender == null ? null :
- new PostInstallData(null, res, () -> onRestoreComplete(res.returnCode,
- mContext, intentSender));
+
+ PostInstallData postInstallData =
+ new PostInstallData(null, res, () -> {
+ clearRolesAndRestorePermissionsForNewUserInstall(packageName,
+ pkgSetting.getInstallReason(userId), userId);
+ if (intentSender != null) {
+ onRestoreComplete(res.returnCode, mContext, intentSender);
+ }
+ });
restoreAndPostInstall(userId, res, postInstallData);
}
} finally {
@@ -13836,6 +13824,19 @@
}
/**
+ * Get the integrity verification timeout.
+ *
+ * @return verification timeout in milliseconds
+ */
+ private long getIntegrityVerificationTimeout() {
+ long timeout = Global.getLong(mContext.getContentResolver(),
+ Global.APP_INTEGRITY_VERIFICATION_TIMEOUT, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
+ // The setting can be used to increase the timeout but not decrease it, since that is
+ // equivalent to disabling the integrity component.
+ return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
+ }
+
+ /**
* Get the default verification agent response code.
*
* @return default verification response code
@@ -15030,8 +15031,7 @@
final Message msg =
mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
msg.arg1 = verificationId;
- // TODO: do we want to use the same timeout?
- mHandler.sendMessageDelayed(msg, getVerificationTimeout());
+ mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
}
}, /* scheduler= */ null,
/* initialCode= */ 0,
@@ -15254,12 +15254,21 @@
&& mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
- try {
- PackageLite packageInfo =
- new PackageParser().parsePackageLite(origin.file, 0);
- packageName = packageInfo.packageName;
- } catch (PackageParserException e) {
- Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
+ ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ new ParseTypeImpl(
+ (changeId, packageName1, targetSdkVersion) -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName1;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ return mPackageParserCallback.isChangeEnabled(changeId,
+ appInfo);
+ }).reset(),
+ origin.file, 0);
+ if (result.isError()) {
+ Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
+ result.getException());
+ } else {
+ packageName = result.getResult().packageName;
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
@@ -15772,7 +15781,6 @@
String returnMsg;
String installerPackageName;
PackageRemovedInfo removedInfo;
- ArrayMap<String, PackageInstalledInfo> addedChildPackages;
// The set of packages consuming this shared library or null if no consumers exist.
ArrayList<AndroidPackage> libraryConsumers;
PackageFreezer freezer;
@@ -15786,37 +15794,21 @@
public void setError(String msg, PackageParserException e) {
setReturnCode(e.error);
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
- final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- addedChildPackages.valueAt(i).setError(msg, e);
- }
Slog.w(TAG, msg, e);
}
public void setError(String msg, PackageManagerException e) {
returnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
- final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- addedChildPackages.valueAt(i).setError(msg, e);
- }
Slog.w(TAG, msg, e);
}
public void setReturnCode(int returnCode) {
this.returnCode = returnCode;
- final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- addedChildPackages.valueAt(i).returnCode = returnCode;
- }
}
private void setReturnMessage(String returnMsg) {
this.returnMsg = returnMsg;
- final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- addedChildPackages.valueAt(i).returnMsg = returnMsg;
- }
}
// In some error cases we want to convey more info back to the observer
@@ -17068,7 +17060,7 @@
parsedPackage.setSigningDetails(args.signingDetails);
} else {
parsedPackage.setSigningDetails(
- ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
+ ParsingPackageUtils.getSigningDetails(parsedPackage, false /* skipVerify */));
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -17366,7 +17358,6 @@
int targetParseFlags = parseFlags;
final PackageSetting ps;
final PackageSetting disabledPs;
- final PackageSetting[] childPackages;
if (replace) {
if (parsedPackage.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
@@ -17900,8 +17891,46 @@
}
@Override
+ public void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.DELETE_PACKAGES, null);
+ Preconditions.checkNotNull(versionedPackage);
+ Preconditions.checkNotNull(observer);
+ final String packageName = versionedPackage.getPackageName();
+ final long versionCode = versionedPackage.getLongVersionCode();
+
+ int installedForUsersCount = 0;
+ synchronized (mLock) {
+ // Normalize package name to handle renamed packages and static libs
+ final String internalPkgName = resolveInternalPackageNameLPr(packageName, versionCode);
+ final PackageSetting ps = mSettings.getPackageLPr(internalPkgName);
+ if (ps != null) {
+ int[] installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
+ installedForUsersCount = installedUsers.length;
+ }
+ }
+
+ if (installedForUsersCount > 1) {
+ deletePackageVersionedInternal(versionedPackage, observer, userId, 0, true);
+ } else {
+ try {
+ observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_INTERNAL_ERROR,
+ null);
+ } catch (RemoteException re) {
+ }
+ }
+ }
+
+ @Override
public void deletePackageVersioned(VersionedPackage versionedPackage,
final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
+ deletePackageVersionedInternal(versionedPackage, observer, userId, deleteFlags, false);
+ }
+
+ private void deletePackageVersionedInternal(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags,
+ final boolean allowSilentUninstall) {
final int callingUid = Binder.getCallingUid();
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
@@ -17922,6 +17951,7 @@
final int uid = Binder.getCallingUid();
if (!isOrphaned(internalPackageName)
+ && !allowSilentUninstall
&& !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
mHandler.post(() -> {
try {
@@ -18329,7 +18359,6 @@
final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0;
info.sendPackageRemovedBroadcasts(killApp);
info.sendSystemPackageUpdatedBroadcasts();
- info.sendSystemPackageAppearedBroadcasts();
}
// Force a gc here.
Runtime.getRuntime().gc();
@@ -18387,7 +18416,6 @@
SparseArray<int[]> broadcastWhitelist;
// Clean up resources deleted packages.
InstallArgs args = null;
- ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
PackageRemovedInfo(PackageSender packageSender) {
this.packageSender = packageSender;
@@ -18403,18 +18431,6 @@
}
}
- void sendSystemPackageAppearedBroadcasts() {
- final int packageCount = (appearedChildPackages != null)
- ? appearedChildPackages.size() : 0;
- for (int i = 0; i < packageCount; i++) {
- PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
- packageSender.sendPackageAddedForNewUsers(installedInfo.name,
- true /*sendBootCompleted*/, false /*startReceiver*/,
- UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers, null,
- DataLoaderType.NONE);
- }
- }
-
private void sendSystemPackageUpdatedBroadcastsInternal() {
Bundle extras = new Bundle(2);
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
@@ -19681,6 +19697,30 @@
}
}
+ private void clearRolesAndRestorePermissionsForNewUserInstall(String packageName,
+ int installReason, @UserIdInt int userId) {
+ // If this app is a browser and it's newly-installed for some
+ // users, clear any default-browser state in those users. The
+ // app's nature doesn't depend on the user, so we can just check
+ // its browser nature in any user and generalize.
+ if (packageIsBrowser(packageName, userId)) {
+ // If this browser is restored from user's backup, do not clear
+ // default-browser state for this user
+ if (installReason != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
+ mPermissionManager.setDefaultBrowser(null, true, true, userId);
+ }
+ }
+
+ // We may also need to apply pending (restored) runtime permission grants
+ // within these users.
+ mPermissionManager.restoreDelayedRuntimePermissions(packageName,
+ UserHandle.of(userId));
+
+ // Persistent preferred activity might have came into effect due to this
+ // install.
+ updateDefaultHomeNotLocked(userId);
+ }
+
@Override
public void resetApplicationPreferences(int userId) {
mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 88f442c..0dc4d13 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -51,7 +51,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -63,6 +62,8 @@
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
@@ -505,6 +506,7 @@
long sessionSize = 0;
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (String inPath : inPaths) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
if (fd == null) {
@@ -512,12 +514,19 @@
throw new IllegalArgumentException("Error: Can't open file: " + inPath);
}
try {
- ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0);
- PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
- null, null);
+ ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(
+ input.reset(), fd.getFileDescriptor(), inPath, 0);
+ if (apkLiteResult.isError()) {
+ throw new IllegalArgumentException(
+ "Error: Failed to parse APK file: " + inPath + ": "
+ + apkLiteResult.getErrorMessage(),
+ apkLiteResult.getException());
+ }
+ PackageLite pkgLite = new PackageLite(null, apkLiteResult.getResult(), null, null,
+ null, null, null, null);
sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
params.sessionParams.abiOverride, fd.getFileDescriptor());
- } catch (PackageParserException | IOException e) {
+ } catch (IOException e) {
getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
throw new IllegalArgumentException(
"Error: Failed to parse APK file: " + inPath, e);
@@ -3163,7 +3172,7 @@
metadata = (streamingVersion == 0) ? Metadata.forDataOnlyStreaming(fileId)
: Metadata.forStreaming(fileId);
try {
- if (V4Signature.readFrom(signature) == null) {
+ if ((signature.length > 0) && (V4Signature.readFrom(signature) == null)) {
getErrPrintWriter().println("V4 signature is invalid in: " + arg);
return 1;
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9a297d6..79805e3 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -61,6 +61,7 @@
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;
@@ -68,6 +69,8 @@
import com.android.internal.content.PackageHelper;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
@@ -109,6 +112,9 @@
private final List<String> mFailedPackageNames = new ArrayList<>();
private String mNativeFailureReason;
+ @GuardedBy("mSuccessfulStagedSessionIds")
+ private final List<Integer> mSuccessfulStagedSessionIds = new ArrayList<>();
+
StagingManager(PackageInstallerService pi, Context context,
Supplier<PackageParser2> packageParserSupplier) {
mPi = pi;
@@ -121,6 +127,34 @@
BackgroundThread.get().getLooper());
}
+ /**
+ This class manages lifecycle events for StagingManager.
+ */
+ public static final class Lifecycle extends SystemService {
+ private static StagingManager sStagingManager;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ void startService(StagingManager stagingManager) {
+ sStagingManager = stagingManager;
+ LocalServices.getService(SystemServiceManager.class).startService(this);
+ }
+
+ @Override
+ public void onStart() {
+ // no-op
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_BOOT_COMPLETED && sStagingManager != null) {
+ sStagingManager.markStagedSessionsAsSuccessful();
+ }
+ }
+ }
+
private void updateStoredSession(@NonNull PackageInstallerSession sessionInfo) {
synchronized (mStagedSessions) {
PackageInstallerSession storedSession = mStagedSessions.get(sessionInfo.sessionId);
@@ -137,6 +171,9 @@
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
+ if (stagedSession.isDestroyed()) {
+ continue;
+ }
result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
}
}
@@ -202,7 +239,7 @@
final IntArray childSessionIds = new IntArray();
if (session.isMultiPackage()) {
for (int id : session.getChildSessionIds()) {
- if (isApexSession(mStagedSessions.get(id))) {
+ if (isApexSession(getStagedSession(id))) {
childSessionIds.add(id);
}
}
@@ -350,13 +387,19 @@
Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
try {
if (supportsCheckpoint() && needsCheckpoint()) {
- mApexManager.revertActiveSessions();
+ // Only revert apex sessions if device supports updating apex
+ if (mApexManager.isApexSupported()) {
+ mApexManager.revertActiveSessions();
+ }
PackageHelper.getStorageManager().abortChanges(
"StagingManager initiated", false /*retry*/);
}
} catch (Exception e) {
Slog.wtf(TAG, "Failed to abort checkpoint", e);
- mApexManager.revertActiveSessions();
+ // Only revert apex sessions if device supports updating apex
+ if (mApexManager.isApexSupported()) {
+ mApexManager.revertActiveSessions();
+ }
mPowerManager.reboot(null);
}
}
@@ -642,7 +685,22 @@
Slog.d(TAG, "Marking session " + session.sessionId + " as applied");
session.setStagedSessionApplied();
if (hasApex) {
- mApexManager.markStagedSessionSuccessful(session.sessionId);
+ try {
+ if (supportsCheckpoint()) {
+ // Store the session ID, which will be marked as successful by ApexManager
+ // upon boot completion.
+ synchronized (mSuccessfulStagedSessionIds) {
+ mSuccessfulStagedSessionIds.add(session.sessionId);
+ }
+ } else {
+ // Mark sessions as successful immediately on non-checkpointing devices.
+ mApexManager.markStagedSessionSuccessful(session.sessionId);
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Checkpoint support unknown, marking session as successful "
+ + "immediately.");
+ mApexManager.markStagedSessionSuccessful(session.sessionId);
+ }
}
}
@@ -797,6 +855,8 @@
+ session.sessionId + " [" + errorMessage + "]");
session.setStagedSessionFailed(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage);
+ mPreRebootVerificationHandler.onPreRebootVerificationComplete(
+ session.sessionId);
return;
}
mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
@@ -880,7 +940,8 @@
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
- if (!stagedSession.isCommitted() || stagedSession.isStagedAndInTerminalState()) {
+ if (!stagedSession.isCommitted() || stagedSession.isStagedAndInTerminalState()
+ || stagedSession.isDestroyed()) {
continue;
}
if (stagedSession.isMultiPackage()) {
@@ -943,27 +1004,68 @@
}
}
- void abortCommittedSession(@NonNull PackageInstallerSession session) {
+ /**
+ * <p>Abort committed staged session
+ *
+ * <p>This method must be called while holding {@link PackageInstallerSession.mLock}.
+ *
+ * <p>The method returns {@code false} to indicate it is not safe to clean up the session from
+ * system yet. When it is safe, the method returns {@code true}.
+ *
+ * <p> When it is safe to clean up, {@link StagingManager} will call
+ * {@link PackageInstallerSession#abandon()} on the session again.
+ *
+ * @return {@code true} if it is safe to cleanup the session resources, otherwise {@code false}.
+ */
+ boolean abortCommittedSessionLocked(@NonNull PackageInstallerSession session) {
+ int sessionId = session.sessionId;
if (session.isStagedSessionApplied()) {
- Slog.w(TAG, "Cannot abort applied session : " + session.sessionId);
- return;
+ Slog.w(TAG, "Cannot abort applied session : " + sessionId);
+ return false;
}
- abortSession(session);
+ if (!session.isDestroyed()) {
+ throw new IllegalStateException("Committed session must be destroyed before aborting it"
+ + " from StagingManager");
+ }
+ if (getStagedSession(sessionId) == null) {
+ Slog.w(TAG, "Session " + sessionId + " has been abandoned already");
+ return false;
+ }
- boolean hasApex = sessionContainsApex(session);
- if (hasApex) {
- ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
- if (apexSession == null || isApexSessionFinalized(apexSession)) {
- Slog.w(TAG,
- "Cannot abort session " + session.sessionId
- + " because it is not active or APEXD is not reachable");
- return;
- }
- try {
- mApexManager.abortStagedSession(session.sessionId);
- } catch (Exception ignore) {
+ // If pre-reboot verification is running, then return false. StagingManager will call
+ // abandon again when pre-reboot verification ends.
+ if (mPreRebootVerificationHandler.isVerificationRunning(sessionId)) {
+ Slog.w(TAG, "Session " + sessionId + " aborted before pre-reboot "
+ + "verification completed.");
+ return false;
+ }
+
+ // A session could be marked ready once its pre-reboot verification ends
+ if (session.isStagedSessionReady()) {
+ if (sessionContainsApex(session)) {
+ try {
+ ApexSessionInfo apexSession =
+ mApexManager.getStagedSessionInfo(session.sessionId);
+ if (apexSession == null || isApexSessionFinalized(apexSession)) {
+ Slog.w(TAG,
+ "Cannot abort session " + session.sessionId
+ + " because it is not active.");
+ } else {
+ mApexManager.abortStagedSession(session.sessionId);
+ }
+ } catch (Exception e) {
+ // Failed to contact apexd service. The apex might still be staged. We can still
+ // safely cleanup the staged session since pre-reboot verification is complete.
+ // Also, cleaning up the stageDir prevents the apex from being activated.
+ Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
+ }
}
}
+
+ // Session was successfully aborted from apexd (if required) and pre-reboot verification
+ // is also complete. It is now safe to clean up the session from system.
+ abortSession(session);
+ return true;
}
private boolean isApexSessionFinalized(ApexSessionInfo session) {
@@ -1042,6 +1144,11 @@
// Final states, nothing to do.
return;
}
+ if (session.isDestroyed()) {
+ // Device rebooted before abandoned session was cleaned up.
+ session.abandon();
+ return;
+ }
if (!session.isStagedSessionReady()) {
// The framework got restarted before the pre-reboot verification could complete,
// restart the verification.
@@ -1062,7 +1169,16 @@
}
}
+ void markStagedSessionsAsSuccessful() {
+ synchronized (mSuccessfulStagedSessionIds) {
+ for (int i = 0; i < mSuccessfulStagedSessionIds.size(); i++) {
+ mApexManager.markStagedSessionSuccessful(mSuccessfulStagedSessionIds.get(i));
+ }
+ }
+ }
+
void systemReady() {
+ new Lifecycle(mContext).startService(this);
// Register the receiver of boot completed intent for staging manager.
mContext.registerReceiver(new BroadcastReceiver() {
@Override
@@ -1124,10 +1240,20 @@
}
}
+ private PackageInstallerSession getStagedSession(int sessionId) {
+ PackageInstallerSession session;
+ synchronized (mStagedSessions) {
+ session = mStagedSessions.get(sessionId);
+ }
+ return session;
+ }
+
private final class PreRebootVerificationHandler extends Handler {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
private boolean mIsReady;
+ @GuardedBy("mVerificationRunning")
+ private final SparseBooleanArray mVerificationRunning = new SparseBooleanArray();
PreRebootVerificationHandler(Looper looper) {
super(looper);
@@ -1155,13 +1281,15 @@
@Override
public void handleMessage(Message msg) {
final int sessionId = msg.arg1;
- final PackageInstallerSession session;
- synchronized (mStagedSessions) {
- session = mStagedSessions.get(sessionId);
- }
- // Maybe session was aborted before pre-reboot verification was complete
+ final PackageInstallerSession session = getStagedSession(sessionId);
if (session == null) {
- Slog.d(TAG, "Stopping pre-reboot verification for sessionId: " + sessionId);
+ Slog.wtf(TAG, "Session disappeared in the middle of pre-reboot verification: "
+ + sessionId);
+ return;
+ }
+ if (session.isDestroyed()) {
+ // No point in running verification on a destroyed session
+ onPreRebootVerificationComplete(sessionId);
return;
}
switch (msg.what) {
@@ -1200,9 +1328,40 @@
mPendingSessionIds.add(sessionId);
return;
}
+
+ PackageInstallerSession session = getStagedSession(sessionId);
+ synchronized (mVerificationRunning) {
+ // Do not start verification on a session that has been abandoned
+ if (session == null || session.isDestroyed()) {
+ return;
+ }
+ Slog.d(TAG, "Starting preRebootVerification for session " + sessionId);
+ mVerificationRunning.put(sessionId, true);
+ }
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
}
+ // Things to do when pre-reboot verification completes for a particular sessionId
+ private void onPreRebootVerificationComplete(int sessionId) {
+ // Remove it from mVerificationRunning so that verification is considered complete
+ synchronized (mVerificationRunning) {
+ Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId);
+ mVerificationRunning.delete(sessionId);
+ }
+ // Check if the session was destroyed while pre-reboot verification was running. If so,
+ // abandon it again.
+ PackageInstallerSession session = getStagedSession(sessionId);
+ if (session != null && session.isDestroyed()) {
+ session.abandon();
+ }
+ }
+
+ private boolean isVerificationRunning(int sessionId) {
+ synchronized (mVerificationRunning) {
+ return mVerificationRunning.get(sessionId);
+ }
+ }
+
private void notifyPreRebootVerification_Start_Complete(int sessionId) {
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APEX, sessionId, 0).sendToTarget();
}
@@ -1221,8 +1380,6 @@
* See {@link PreRebootVerificationHandler} to see all nodes of pre reboot verification
*/
private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) {
- Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);
-
if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// If rollback is enabled for this session, we call through to the RollbackManager
// with the list of sessions it must enable rollback for. Note that
@@ -1269,6 +1426,7 @@
}
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
+ onPreRebootVerificationComplete(session.sessionId);
return;
}
@@ -1301,6 +1459,7 @@
// TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
+ onPreRebootVerificationComplete(session.sessionId);
}
}
@@ -1323,9 +1482,18 @@
Slog.e(TAG, "Failed to get hold of StorageManager", e);
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
"Failed to get hold of StorageManager");
+ onPreRebootVerificationComplete(session.sessionId);
return;
}
+ // Stop pre-reboot verification before marking session ready. From this point on, if we
+ // abandon the session then it will be cleaned up immediately. If session is abandoned
+ // after this point, then even if for some reason system tries to install the session
+ // or activate its apex, there won't be any files to work with as they will be cleaned
+ // up by the system as part of abandonment. If session is abandoned before this point,
+ // then the session is already destroyed and cannot be marked ready anymore.
+ onPreRebootVerificationComplete(session.sessionId);
+
// Proactively mark session as ready before calling apexd. Although this call order
// looks counter-intuitive, this is the easiest way to ensure that session won't end up
// in the inconsistent state:
@@ -1337,15 +1505,16 @@
// only apex part of the train will be applied, leaving device in an inconsistent state.
Slog.d(TAG, "Marking session " + session.sessionId + " as ready");
session.setStagedSessionReady();
- final boolean hasApex = sessionContainsApex(session);
- if (!hasApex) {
- // Session doesn't contain apex, nothing to do.
- return;
- }
- try {
- mApexManager.markStagedSessionReady(session.sessionId);
- } catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
+ if (session.isStagedSessionReady()) {
+ final boolean hasApex = sessionContainsApex(session);
+ if (hasApex) {
+ try {
+ mApexManager.markStagedSessionReady(session.sessionId);
+ } catch (PackageManagerException e) {
+ session.setStagedSessionFailed(e.error, e.getMessage());
+ return;
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index eb79b6e..d3cd1a9 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -37,6 +37,9 @@
},
{
"include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
+ },
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerTest"
}
]
},
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e6af86e..29428a2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1330,6 +1330,9 @@
return userTypeDetails.getBadgeLabel(badgeIndex);
}
+ /**
+ * @return the color (not the resource ID) to be used for the user's badge in light theme
+ */
@Override
public @ColorRes int getUserBadgeColorResId(@UserIdInt int userId) {
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
@@ -1337,11 +1340,26 @@
final UserInfo userInfo = getUserInfoNoChecks(userId);
final UserTypeDetails userTypeDetails = getUserTypeDetails(userInfo);
if (userInfo == null || userTypeDetails == null || !userTypeDetails.hasBadge()) {
+ Slog.e(LOG_TAG, "Requested badge dark color for non-badged user " + userId);
+ return Resources.ID_NULL;
+ }
+ return userTypeDetails.getBadgeColor(userInfo.profileBadge);
+ }
+
+ /**
+ * @return the color (not the resource ID) to be used for the user's badge in dark theme
+ */
+ @Override
+ public @ColorRes int getUserBadgeDarkColorResId(@UserIdInt int userId) {
+ checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
+ "getUserBadgeDarkColorResId");
+ final UserInfo userInfo = getUserInfoNoChecks(userId);
+ final UserTypeDetails userTypeDetails = getUserTypeDetails(userInfo);
+ if (userInfo == null || userTypeDetails == null || !userTypeDetails.hasBadge()) {
Slog.e(LOG_TAG, "Requested badge color for non-badged user " + userId);
return Resources.ID_NULL;
}
- final int badgeIndex = userInfo.profileBadge;
- return userTypeDetails.getBadgeColor(badgeIndex);
+ return userTypeDetails.getDarkThemeBadgeColor(userInfo.profileBadge);
}
@Override
@@ -4516,8 +4534,8 @@
switch(cmd) {
case "list":
return runList(pw, shell);
- case "list-missing-system-packages":
- return runListMissingSystemPackages(pw, shell);
+ case "report-system-user-package-whitelist-problems":
+ return runReportPackageWhitelistProblems(pw, shell);
default:
return shell.handleDefaultCommands(cmd);
}
@@ -4584,17 +4602,22 @@
}
}
- private int runListMissingSystemPackages(PrintWriter pw, Shell shell) {
+ private int runReportPackageWhitelistProblems(PrintWriter pw, Shell shell) {
boolean verbose = false;
- boolean force = false;
+ boolean criticalOnly = false;
+ int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE;
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
case "-v":
+ case "--verbose":
verbose = true;
break;
- case "--force":
- force = true;
+ case "--critical-only":
+ criticalOnly = true;
+ break;
+ case "--mode":
+ mode = Integer.parseInt(shell.getNextArgRequired());
break;
default:
pw.println("Invalid option: " + opt);
@@ -4602,8 +4625,12 @@
}
}
+ Slog.d(LOG_TAG, "runReportPackageWhitelistProblems(): verbose=" + verbose
+ + ", criticalOnly=" + criticalOnly
+ + ", mode=" + UserSystemPackageInstaller.modeToString(mode));
+
try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
- mSystemPackageInstaller.dumpMissingSystemPackages(ipw, force, verbose);
+ mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly);
}
return 0;
}
@@ -5176,13 +5203,18 @@
final PrintWriter pw = getOutPrintWriter();
pw.println("User manager (user) commands:");
pw.println(" help");
- pw.println(" Print this help text.");
+ pw.println(" Prints this help text.");
pw.println("");
pw.println(" list [-v] [-all]");
pw.println(" Prints all users on the system.");
- pw.println(" list-missing-system-packages [-v] [--force]");
- pw.println(" Prints all system packages that were not explicitly configured to be "
- + "installed.");
+ pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] "
+ + "[--critical-only] [--mode MODE]");
+ pw.println(" Reports all issues on user-type package whitelist XML files. Options:");
+ pw.println(" -v | --verbose : shows extra info, like number of issues");
+ pw.println(" --critical-only: show only critical issues, excluding warnings");
+ pw.println(" --mode MODE: shows what errors would be if device used mode MODE (where"
+ + " MODE is the whitelist mode integer as defined by "
+ + "config_userTypePackageWhitelistMode)");
}
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 0b6024a..1fec8aa 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -208,7 +208,6 @@
Sets.newArraySet(
UserManager.DISALLOW_CONFIG_DATE_TIME,
UserManager.DISALLOW_CAMERA,
- UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_BLUETOOTH,
UserManager.DISALLOW_BLUETOOTH_SHARING,
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index cd1087f5..530c115 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -27,7 +27,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Pair;
+import android.util.DebugUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -41,6 +41,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -111,14 +112,20 @@
* frameworks/base/core/res/res/values/config.xml
*/
static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
+
+ // NOTE: flags below are public so they can used by DebugUtils.flagsToString. And this class
+ // itself is package-protected, so it doesn't matter...
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
+ // Used by Shell command only
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_NONE = -1000;
+
@IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
@@ -266,58 +273,56 @@
if (!isLogMode(mode) && !isEnforceMode(mode)) {
return;
}
- final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode);
- final int size = warnings.size();
- if (size == 0) {
- Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): no warnings");
- return;
- }
+ Slog.v(TAG, "Checking that all system packages are whitelisted.");
- if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) {
- // Only shows whether all whitelisted packages are indeed on the system.
- for (int i = 0; i < size; i++) {
- final Pair<Boolean, String> pair = warnings.get(i);
- final boolean isSevere = pair.first;
- if (!isSevere) {
- final String msg = pair.second;
- Slog.w(TAG, msg);
- }
+ // Check whether all whitelisted packages are indeed on the system.
+ final List<String> warnings = getPackagesWhitelistWarnings();
+ final int numberWarnings = warnings.size();
+ if (numberWarnings == 0) {
+ Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
+ + ") has no warnings");
+ } else {
+ Slog.w(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
+ + ") has " + numberWarnings + " warnings:");
+ for (int i = 0; i < numberWarnings; i++) {
+ Slog.w(TAG, warnings.get(i));
}
+ }
+
+ // Check whether all system packages are indeed whitelisted.
+ if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) {
return;
}
- Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): " + size + " warnings");
+ final List<String> errors = getPackagesWhitelistErrors(mode);
+ final int numberErrors = errors.size();
+
+ if (numberErrors == 0) {
+ Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
+ + ") has no errors");
+ return;
+ }
+ Slog.e(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) + ") has "
+ + numberErrors + " errors:");
+
boolean doWtf = !isImplicitWhitelistMode(mode);
- for (int i = 0; i < size; i++) {
- final Pair<Boolean, String> pair = warnings.get(i);
- final boolean isSevere = pair.first;
- final String msg = pair.second;
- if (isSevere) {
- if (doWtf) {
- Slog.wtf(TAG, msg);
- } else {
- Slog.e(TAG, msg);
- }
+ for (int i = 0; i < numberErrors; i++) {
+ final String msg = errors.get(i);
+ if (doWtf) {
+ Slog.wtf(TAG, msg);
} else {
- Slog.w(TAG, msg);
+ Slog.e(TAG, msg);
}
}
}
- // TODO: method below was created to refactor the one-time logging logic so it can be used on
- // dump / cmd as well. It could to be further refactored (for example, creating a new
- // structure for the warnings so it doesn't need a Pair).
/**
- * Gets warnings for system user whitelisting.
- *
- * @return list of warnings, where {@code Pair.first} is the severity ({@code true} for WTF,
- * {@code false} for WARN) and {@code Pair.second} the message.
+ * Gets packages that are listed in the whitelist XML but are not present on the system image.
*/
@NonNull
- private List<Pair<Boolean, String>> checkSystemPackagesWhitelistWarnings(
- @PackageWhitelistMode int mode) {
+ private List<String> getPackagesWhitelistWarnings() {
final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
- final List<Pair<Boolean, String>> warnings = new ArrayList<>();
+ final List<String> warnings = new ArrayList<>();
final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Check whether all whitelisted packages are indeed on the system.
@@ -326,25 +331,39 @@
for (String pkgName : allWhitelistedPackages) {
final AndroidPackage pkg = pmInt.getPackage(pkgName);
if (pkg == null) {
- warnings.add(new Pair<>(false, String.format(notPresentFmt, pkgName)));
+ warnings.add(String.format(notPresentFmt, pkgName));
} else if (!pkg.isSystem()) {
- warnings.add(new Pair<>(false, String.format(notSystemFmt, pkgName)));
+ warnings.add(String.format(notSystemFmt, pkgName));
}
}
+ return warnings;
+ }
+
+ /**
+ * Gets packages that are not listed in the whitelist XMLs when they should be.
+ */
+ @NonNull
+ private List<String> getPackagesWhitelistErrors(@PackageWhitelistMode int mode) {
+ if ((!isEnforceMode(mode) || isImplicitWhitelistMode(mode))) {
+ return Collections.emptyList();
+ }
+
+ final List<String> errors = new ArrayList<>();
+ final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
+ final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Check whether all system packages are indeed whitelisted.
final String logMessageFmt = "System package %s is not whitelisted using "
+ "'install-in-user-type' in SystemConfig for any user types!";
- final boolean isSevere = isEnforceMode(mode);
pmInt.forEachPackage(pkg -> {
if (!pkg.isSystem()) return;
final String pkgName = pkg.getManifestPackageName();
if (!allWhitelistedPackages.contains(pkgName)) {
- warnings.add(new Pair<>(isSevere, String.format(logMessageFmt, pkgName)));
+ errors.add(String.format(logMessageFmt, pkgName));
}
});
- return warnings;
+ return errors;
}
/** Whether to only install system packages in new users for which they are whitelisted. */
@@ -420,10 +439,28 @@
if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
return runtimeMode;
}
+ return getDeviceDefaultWhitelistMode();
+ }
+
+ /** Gets the PackageWhitelistMode as defined by {@code config_userTypePackageWhitelistMode}. */
+ private @PackageWhitelistMode int getDeviceDefaultWhitelistMode() {
return Resources.getSystem()
.getInteger(com.android.internal.R.integer.config_userTypePackageWhitelistMode);
}
+ static @NonNull String modeToString(@PackageWhitelistMode int mode) {
+ // Must handle some types separately because they're not bitwise flags
+ switch (mode) {
+ case USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT:
+ return "DEVICE_DEFAULT";
+ case USER_TYPE_PACKAGE_WHITELIST_MODE_NONE:
+ return "NONE";
+ default:
+ return DebugUtils.flagsToString(UserSystemPackageInstaller.class,
+ "USER_TYPE_PACKAGE_WHITELIST_MODE_", mode);
+ }
+ }
+
/**
* Gets the system packages names that should be installed on the given user.
* See {@link #getInstallablePackagesForUserType(String)}.
@@ -703,34 +740,48 @@
pw.decreaseIndent(); pw.decreaseIndent();
pw.increaseIndent();
- dumpMissingSystemPackages(pw, /* force= */ true, /* verbose= */ true);
+ dumpPackageWhitelistProblems(pw, mode, /* verbose= */ true, /* criticalOnly= */ false);
pw.decreaseIndent();
}
- void dumpMissingSystemPackages(IndentingPrintWriter pw, boolean force, boolean verbose) {
- final int mode = getWhitelistMode();
- final boolean show = force || (isEnforceMode(mode) && !isImplicitWhitelistMode(mode));
- if (!show) return;
+ void dumpPackageWhitelistProblems(IndentingPrintWriter pw, @PackageWhitelistMode int mode,
+ boolean verbose, boolean criticalOnly) {
+ // Handle special cases first
+ if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_NONE) {
+ mode = getWhitelistMode();
+ } else if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
+ mode = getDeviceDefaultWhitelistMode();
+ }
+ if (criticalOnly) {
+ // Flip-out log mode
+ mode &= ~USER_TYPE_PACKAGE_WHITELIST_MODE_LOG;
+ }
+ Slog.v(TAG, "dumpPackageWhitelistProblems(): using mode " + modeToString(mode));
- final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode);
- final int size = warnings.size();
+ final List<String> errors = getPackagesWhitelistErrors(mode);
+ showIssues(pw, verbose, errors, "errors");
+ if (criticalOnly) return;
+
+ final List<String> warnings = getPackagesWhitelistWarnings();
+ showIssues(pw, verbose, warnings, "warnings");
+ }
+
+ private static void showIssues(IndentingPrintWriter pw, boolean verbose, List<String> issues,
+ String issueType) {
+ final int size = issues.size();
if (size == 0) {
if (verbose) {
- pw.println("All system packages are accounted for");
+ pw.print("No "); pw.println(issueType);
}
return;
}
-
if (verbose) {
- pw.print(size); pw.println(" warnings for system user:");
+ pw.print(size); pw.print(' '); pw.println(issueType);
pw.increaseIndent();
}
for (int i = 0; i < size; i++) {
- final Pair<Boolean, String> pair = warnings.get(i);
- final String lvl = pair.first ? "WTF" : "WARN";
- final String msg = pair.second;
- pw.print(lvl); pw.print(": "); pw.println(msg);
+ pw.println(issues.get(i));
}
if (verbose) {
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 826cd3f7..be6880e 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -116,11 +116,23 @@
*/
private final @Nullable int[] mBadgeColors;
+ /**
+ * Resource ID ({@link ColorRes}) of the colors badge put on icons when in dark theme.
+ * (The value is a resource ID referring to the color; it is not the color value itself).
+ *
+ * <p>This is an array because, in general, there may be multiple users of the same user type.
+ * In this case, the user is indexed according to its {@link UserInfo#profileBadge}.
+ *
+ * <p>Must be set if mIconBadge is set.
+ */
+ private final @Nullable int[] mDarkThemeBadgeColors;
+
private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
@UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
int maxAllowedPerParent,
int iconBadge, int badgePlain, int badgeNoBackground,
@Nullable int[] badgeLabels, @Nullable int[] badgeColors,
+ @Nullable int[] darkThemeBadgeColors,
@Nullable Bundle defaultRestrictions) {
this.mName = name;
this.mEnabled = enabled;
@@ -136,6 +148,7 @@
this.mLabel = label;
this.mBadgeLabels = badgeLabels;
this.mBadgeColors = badgeColors;
+ this.mDarkThemeBadgeColors = darkThemeBadgeColors;
}
/**
@@ -222,6 +235,19 @@
return mBadgeColors[Math.min(badgeIndex, mBadgeColors.length - 1)];
}
+ /**
+ * Returns the Resource ID of the badgeIndexth dark theme badge color, where the badgeIndex is
+ * expected to be the {@link UserInfo#profileBadge} of the user.
+ * If dark theme badge colors haven't been set, use the light theme badge color.
+ * If badgeIndex exceeds the number of colors, returns the color for the highest index.
+ */
+ public @ColorRes int getDarkThemeBadgeColor(int badgeIndex) {
+ if (mDarkThemeBadgeColors == null || mDarkThemeBadgeColors.length == 0 || badgeIndex < 0) {
+ return getBadgeColor(badgeIndex);
+ }
+ return mDarkThemeBadgeColors[Math.min(badgeIndex, mDarkThemeBadgeColors.length - 1)];
+ }
+
public boolean isProfile() {
return (mBaseType & UserInfo.FLAG_PROFILE) != 0;
}
@@ -255,8 +281,27 @@
pw.print(prefix); pw.print("mDefaultUserInfoFlags: ");
pw.println(UserInfo.flagsToString(mDefaultUserInfoPropertyFlags));
pw.print(prefix); pw.print("mLabel: "); pw.println(mLabel);
- pw.print(prefix); pw.println("mDefaultRestrictions: ");
- UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", mDefaultRestrictions);
+
+ if (isSystem()) {
+ pw.print(prefix); pw.println("config_defaultFirstUserRestrictions: ");
+ try {
+ final Bundle restrictions = new Bundle();
+ final String[] defaultFirstUserRestrictions = Resources.getSystem().getStringArray(
+ com.android.internal.R.array.config_defaultFirstUserRestrictions);
+ for (String userRestriction : defaultFirstUserRestrictions) {
+ if (UserRestrictionsUtils.isValidRestriction(userRestriction)) {
+ restrictions.putBoolean(userRestriction, true);
+ }
+ }
+ UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", restrictions);
+ } catch (Resources.NotFoundException e) {
+ pw.print(prefix); pw.println(" none - resource not found");
+ }
+ } else {
+ pw.print(prefix); pw.println("mDefaultRestrictions: ");
+ UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", mDefaultRestrictions);
+ }
+
pw.print(prefix); pw.print("mIconBadge: "); pw.println(mIconBadge);
pw.print(prefix); pw.print("mBadgePlain: "); pw.println(mBadgePlain);
pw.print(prefix); pw.print("mBadgeNoBackground: "); pw.println(mBadgeNoBackground);
@@ -264,6 +309,8 @@
pw.println(mBadgeLabels != null ? mBadgeLabels.length : "0(null)");
pw.print(prefix); pw.print("mBadgeColors.length: ");
pw.println(mBadgeColors != null ? mBadgeColors.length : "0(null)");
+ pw.print(prefix); pw.print("mDarkThemeBadgeColors.length: ");
+ pw.println(mDarkThemeBadgeColors != null ? mDarkThemeBadgeColors.length : "0(null)");
}
/** Builder for a {@link UserTypeDetails}; see that class for documentation. */
@@ -279,6 +326,7 @@
private int mLabel = Resources.ID_NULL;
private @Nullable int[] mBadgeLabels = null;
private @Nullable int[] mBadgeColors = null;
+ private @Nullable int[] mDarkThemeBadgeColors = null;
private @DrawableRes int mIconBadge = Resources.ID_NULL;
private @DrawableRes int mBadgePlain = Resources.ID_NULL;
private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
@@ -323,6 +371,14 @@
return this;
}
+ /**
+ * The badge colors when the badge is on a dark background.
+ */
+ public Builder setDarkThemeBadgeColors(@ColorRes int ... darkThemeBadgeColors) {
+ mDarkThemeBadgeColors = darkThemeBadgeColors;
+ return this;
+ }
+
public Builder setIconBadge(@DrawableRes int badgeIcon) {
mIconBadge = badgeIcon;
return this;
@@ -366,10 +422,10 @@
Preconditions.checkArgument(mBadgeColors != null && mBadgeColors.length != 0,
"UserTypeDetails " + mName + " has badge but no badgeColors.");
}
-
return new UserTypeDetails(mName, mEnabled, mMaxAllowed, mBaseType,
mDefaultUserInfoPropertyFlags, mLabel, mMaxAllowedPerParent,
mIconBadge, mBadgePlain, mBadgeNoBackground, mBadgeLabels, mBadgeColors,
+ mDarkThemeBadgeColors == null ? mBadgeColors : mDarkThemeBadgeColors,
mDefaultRestrictions);
}
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7d45516..2e8a267 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -116,6 +116,10 @@
com.android.internal.R.color.profile_badge_1,
com.android.internal.R.color.profile_badge_2,
com.android.internal.R.color.profile_badge_3)
+ .setDarkThemeBadgeColors(
+ com.android.internal.R.color.profile_badge_1_dark,
+ com.android.internal.R.color.profile_badge_2_dark,
+ com.android.internal.R.color.profile_badge_3_dark)
.setDefaultRestrictions(null);
}
@@ -292,6 +296,8 @@
setResAttributeArray(parser, builder::setBadgeLabels);
} else if (isProfile && "badge-colors".equals(childName)) {
setResAttributeArray(parser, builder::setBadgeColors);
+ } else if (isProfile && "badge-colors-dark".equals(childName)) {
+ setResAttributeArray(parser, builder::setDarkThemeBadgeColors);
} else {
Slog.w(LOG_TAG, "Unrecognized tag " + childName + " in "
+ parser.getPositionDescription());
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index e860c48..1145057 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -25,6 +25,7 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
@@ -35,7 +36,7 @@
import android.util.DisplayMetrics;
import android.util.Slog;
-import com.android.server.compat.PlatformCompat;
+import com.android.internal.compat.IPlatformCompat;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -58,14 +59,21 @@
*
* This must be called inside the system process as it relies on {@link ServiceManager}.
*/
+ @NonNull
public static PackageParser2 forParsingFileWithDefaults() {
- PlatformCompat platformCompat =
- (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
return new PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
null /* displayMetrics */, null /* cacheDir */, new Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return platformCompat.isChangeEnabled(changeId, appInfo);
+ try {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ } catch (Exception e) {
+ // This shouldn't happen, but assume enforcement if it does
+ Slog.wtf(ParsingUtils.TAG, "IPlatformCompat query failed", e);
+ return true;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 9051d85..8f3bf39 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -408,6 +408,25 @@
}
grantRuntimePermissionsForSystemPackage(pm, userId, pkg);
}
+
+ // Grant READ_PHONE_STATE to all system apps that have READ_PRIVILEGED_PHONE_STATE
+ for (PackageInfo pkg : packages) {
+ if (pkg == null
+ || !doesPackageSupportRuntimePermissions(pkg)
+ || ArrayUtils.isEmpty(pkg.requestedPermissions)
+ || !pkg.applicationInfo.isPrivilegedApp()) {
+ continue;
+ }
+ for (String permission : pkg.requestedPermissions) {
+ if (Manifest.permission.READ_PRIVILEGED_PHONE_STATE.equals(permission)) {
+ grantRuntimePermissions(pm, pkg,
+ Collections.singleton(Manifest.permission.READ_PHONE_STATE),
+ true, // systemFixed
+ userId);
+ }
+ }
+ }
+
}
@SafeVarargs
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 f178903..7d49f78 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -149,6 +149,8 @@
import libcore.util.EmptyArray;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -417,6 +419,11 @@
LocalServices.addService(PermissionManagerInternal.class, localService);
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.getSystemService(PermissionControllerManager.class).dump(fd, args);
+ }
+
/**
* Creates and returns an initialized, internal service for use by other components.
* <p>
@@ -1282,6 +1289,7 @@
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
final int callingUid = Binder.getCallingUid();
+ final int packageUid = UserHandle.getUid(userId, pkg.getUid());
if (!checkAutoRevokeAccess(pkg, callingUid)) {
return false;
@@ -1289,7 +1297,7 @@
if (mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
- callingUid, packageName)
+ packageUid, packageName)
!= MODE_ALLOWED) {
// Whitelist user set - don't override
return false;
@@ -1298,7 +1306,7 @@
final long identity = Binder.clearCallingIdentity();
try {
mAppOpsManager.setMode(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
- callingUid, packageName,
+ packageUid, packageName,
whitelisted ? MODE_IGNORED : MODE_ALLOWED);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1331,6 +1339,7 @@
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
final int callingUid = Binder.getCallingUid();
+ final int packageUid = UserHandle.getUid(userId, pkg.getUid());
if (!checkAutoRevokeAccess(pkg, callingUid)) {
return false;
@@ -1339,7 +1348,7 @@
final long identity = Binder.clearCallingIdentity();
try {
return mAppOpsManager.checkOpNoThrow(
- AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, callingUid, packageName)
+ AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, packageUid, packageName)
== MODE_IGNORED;
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 6eba59a..39f7ac0 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -16,6 +16,8 @@
package com.android.server.policy;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -336,6 +338,8 @@
}
});
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ // Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports
+ mDialog.getWindow().setFlags(FLAG_ALT_FOCUSABLE_IM, FLAG_ALT_FOCUSABLE_IM);
dialog.setOnDismissListener(this);
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 7121b29..76c6a7a 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -25,6 +25,8 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ALL;
@@ -45,7 +47,6 @@
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PermissionInfo;
import android.os.Build;
-import android.os.Handler;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -57,7 +58,6 @@
import android.telecom.TelecomManager;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Log;
import android.util.LongSparseLongArray;
import android.util.Pair;
import android.util.Slog;
@@ -93,6 +93,7 @@
public final class PermissionPolicyService extends SystemService {
private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 10000;
private final Object mLock = new Object();
@@ -208,15 +209,21 @@
for (int i = 0; i < appOpPermissionInfosSize; i++) {
final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i);
- final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermissionInfo.name);
- if (appOpCode != OP_NONE) {
- mAppOpPermissions.add(appOpPermissionInfo.name);
-
- try {
- appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback);
- } catch (RemoteException e) {
- Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e);
- }
+ switch (appOpPermissionInfo.name) {
+ case android.Manifest.permission.ACCESS_NOTIFICATIONS:
+ case android.Manifest.permission.MANAGE_IPSEC_TUNNELS:
+ continue;
+ default:
+ final int appOpCode = AppOpsManager.permissionToOpCode(
+ appOpPermissionInfo.name);
+ if (appOpCode != OP_NONE) {
+ mAppOpPermissions.add(appOpPermissionInfo.name);
+ try {
+ appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback);
+ } catch (RemoteException e) {
+ Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e);
+ }
+ }
}
}
@@ -359,7 +366,7 @@
// Force synchronization as permissions might have changed
synchronizePermissionsAndAppOpsForUser(userId);
- //restoreReadPhoneStatePermissions(userId);
+ restoreReadPhoneStatePermissions(userId);
// Tell observers we are initialized for this user.
if (callback != null) {
@@ -372,8 +379,6 @@
* TODO ntmyren: Remove once propagated, and state is repaired
*/
private void restoreReadPhoneStatePermissions(int userId) {
- PermissionControllerManager manager = new PermissionControllerManager(this.getContext(),
- Handler.getMain());
PackageManager pm = getContext().getPackageManager();
List<PackageInfo> packageInfos = pm.getInstalledPackagesAsUser(
MATCH_ALL | GET_PERMISSIONS, userId);
@@ -383,26 +388,21 @@
continue;
}
- boolean hasReadPhoneState = false;
+ UserHandle user = UserHandle.getUserHandleForUid(pI.applicationInfo.uid);
for (int j = pI.requestedPermissions.length - 1; j >= 0; j--) {
if (pI.requestedPermissions[j].equals(READ_PHONE_STATE)) {
- hasReadPhoneState = true;
+ int flags = pm.getPermissionFlags(READ_PHONE_STATE, pI.packageName, user);
+ // If the app is auto revoked for read phone state, and is only user sensitive
+ // when granted, clear auto revoked flag.
+ if ((flags & FLAG_PERMISSION_AUTO_REVOKED) != 0
+ && (flags & FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0
+ && (flags & FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0) {
+ pm.updatePermissionFlags(READ_PHONE_STATE, pI.packageName,
+ FLAG_PERMISSION_AUTO_REVOKED, 0, user);
+ }
+ break;
}
}
- if (!hasReadPhoneState) {
- continue;
- }
-
- Log.i(LOG_TAG, "Updating read phone state for " + pI.packageName + " "
- + pI.applicationInfo.uid);
- manager.updateUserSensitiveForApp(pI.applicationInfo.uid);
-
- UserHandle user = UserHandle.getUserHandleForUid(pI.applicationInfo.uid);
- int permFlags = pm.getPermissionFlags(READ_PHONE_STATE, pI.packageName, user);
- if ((permFlags & FLAG_PERMISSION_AUTO_REVOKED) != 0) {
- pm.updatePermissionFlags(READ_PHONE_STATE, pI.packageName,
- FLAG_PERMISSION_AUTO_REVOKED, 0, user);
- }
}
}
@@ -454,7 +454,8 @@
throw new IllegalStateException(e);
}
- permissionControllerManager.updateUserSensitive();
+ FgThread.getHandler().postDelayed(permissionControllerManager::updateUserSensitive,
+ USER_SENSITIVE_UPDATE_DELAY_MS);
packageManagerInternal.updateRuntimePermissionsFingerprint(userId);
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index da07223..b3e162d 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -56,6 +56,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
@@ -790,6 +791,7 @@
// in a higher layer than TYPE_APPLICATION_OVERLAY.
return canAddInternalSystemWindow ? 13 : 10;
case TYPE_APPLICATION_OVERLAY:
+ case TYPE_TRUSTED_APPLICATION_OVERLAY:
return 12;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 199cb49..0b95be1 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -413,6 +413,7 @@
// Start input as soon as we start waking up or going to sleep.
mInputManagerInternal.setInteractive(interactive);
+ mInputMethodManagerInternal.setInteractive(interactive);
// Notify battery stats.
try {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 6726cc8..f075790 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -37,6 +37,9 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -298,10 +301,7 @@
}
if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
String packageName = intent.getData().getSchemeSpecificPart();
- if (LOCAL_LOGV) {
- Slog.v(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED"
- + " pkg=" + packageName);
- }
+ Slog.i(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED pkg=" + packageName);
onPackageFullyRemoved(packageName);
}
}
@@ -791,13 +791,15 @@
}
// Get information about the package to be installed.
- PackageParser.PackageLite newPackage;
- try {
- newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
- } catch (PackageParser.PackageParserException e) {
- Slog.e(TAG, "Unable to parse new package", e);
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ ParseResult<PackageParser.ApkLite> parseResult = ApkLiteParseUtils.parseApkLite(
+ input.reset(), new File(session.resolvedBaseCodePath), 0);
+ if (parseResult.isError()) {
+ Slog.e(TAG, "Unable to parse new package: " + parseResult.getErrorMessage(),
+ parseResult.getException());
return false;
}
+ PackageParser.ApkLite newPackage = parseResult.getResult();
String packageName = newPackage.packageName;
Slog.i(TAG, "Enabling rollback for install of " + packageName
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index b0c702f..9871623 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -21,15 +21,19 @@
import static android.app.usage.NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.os.Debug.getIonHeapsSizeKb;
import static android.os.Process.getUidForPid;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
+import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
import static android.util.MathUtils.abs;
import static android.util.MathUtils.constrain;
import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_TRUNCATE_TIMESTAMP;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -37,6 +41,7 @@
import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs;
import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
+import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MICROSECONDS;
import android.annotation.NonNull;
@@ -132,6 +137,7 @@
import com.android.internal.os.PowerProfile;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.StoragedUidIoStatsReader;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.BatteryService;
import com.android.server.BinderCallsStatsService;
@@ -201,6 +207,12 @@
private static final long MILLIS_PER_SEC = 1000;
private static final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
+ /**
+ * The default bucket duration used when query a snapshot from NetworkStatsService.
+ * The value should be sync with NetworkStatsService#DefaultNetworkStatsSettings#getUidConfig.
+ */
+ private static final long NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS = HOURS.toMillis(2);
+
private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
private static final int CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES = 8;
private static final int OP_FLAGS_PULLED = OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXY;
@@ -277,6 +289,14 @@
private StatsPullAtomCallbackImpl mStatsCallbackImpl;
private int mAppOpsSamplingRate = 0;
+ private final ArraySet<Integer> mDangerousAppOpsList = new ArraySet<>();
+
+ // Baselines that stores list of NetworkStats right after initializing, with associated
+ // information. This is used to calculate difference when pulling
+ // {Mobile|Wifi}BytesTransfer* atoms. Note that this is not thread-safe, and must
+ // only be accessed on the background thread.
+ @NonNull
+ private final List<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
public StatsPullAtomService(Context context) {
super(context);
@@ -301,13 +321,10 @@
try {
switch (atomTag) {
case FrameworkStatsLog.WIFI_BYTES_TRANSFER:
- return pullWifiBytesTransfer(atomTag, data, false);
case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG:
- return pullWifiBytesTransfer(atomTag, data, true);
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
- return pullMobileBytesTransfer(atomTag, data, false);
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
- return pullMobileBytesTransfer(atomTag, data, true);
+ return pullDataBytesTransfer(atomTag, data);
case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER:
return pullBluetoothBytesTransfer(atomTag, data);
case FrameworkStatsLog.KERNEL_WAKELOCK:
@@ -422,6 +439,8 @@
return pullAttributedAppOps(atomTag, data);
case FrameworkStatsLog.SETTING_SNAPSHOT:
return pullSettingsStats(atomTag, data);
+ case FrameworkStatsLog.DISPLAY_WAKE_REASON:
+ return pullDisplayWakeStats(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -443,9 +462,12 @@
BackgroundThread.getHandler().post(() -> {
nativeInit();
initializePullersState();
- registerAllPullers();
+ registerPullers();
registerEventListeners();
});
+ } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ // Network stats related pullers can only be initialized after service is ready.
+ BackgroundThread.getHandler().post(() -> initAndRegisterNetworkStatsPullers());
}
}
@@ -498,6 +520,25 @@
} catch (RemoteException e) {
Slog.e(TAG, "failed to initialize healthHalWrapper");
}
+
+ // Initialize list of AppOps related to DangerousPermissions
+ PackageManager pm = mContext.getPackageManager();
+ for (int op = 0; op < AppOpsManager._NUM_OP; op++) {
+ String perm = AppOpsManager.opToPermission(op);
+ if (perm == null) {
+ continue;
+ } else {
+ PermissionInfo permInfo;
+ try {
+ permInfo = pm.getPermissionInfo(perm, 0);
+ if (permInfo.getProtection() == PROTECTION_DANGEROUS) {
+ mDangerousAppOpsList.add(op);
+ }
+ } catch (PackageManager.NameNotFoundException exception) {
+ continue;
+ }
+ }
+ }
}
void registerEventListeners() {
@@ -520,15 +561,11 @@
}
}
- void registerAllPullers() {
+ void registerPullers() {
if (DEBUG) {
- Slog.d(TAG, "Registering all pullers with statsd");
+ Slog.d(TAG, "Registering pullers with statsd");
}
mStatsCallbackImpl = new StatsPullAtomCallbackImpl();
- registerWifiBytesTransfer();
- registerWifiBytesTransferBackground();
- registerMobileBytesTransfer();
- registerMobileBytesTransferBackground();
registerBluetoothBytesTransfer();
registerKernelWakelock();
registerCpuTimePerFreq();
@@ -587,6 +624,27 @@
registerBatteryVoltage();
registerBatteryCycleCount();
registerSettingsStats();
+ registerDisplayWakeStats();
+ }
+
+ private void initAndRegisterNetworkStatsPullers() {
+ if (DEBUG) {
+ Slog.d(TAG, "Registering NetworkStats pullers with statsd");
+ }
+ // Initialize NetworkStats baselines.
+ mNetworkStatsBaselines.addAll(
+ collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.WIFI_BYTES_TRANSFER));
+ mNetworkStatsBaselines.addAll(
+ collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG));
+ mNetworkStatsBaselines.addAll(
+ collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.MOBILE_BYTES_TRANSFER));
+ mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom(
+ FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG));
+
+ registerWifiBytesTransfer();
+ registerWifiBytesTransferBackground();
+ registerMobileBytesTransfer();
+ registerMobileBytesTransferBackground();
}
/**
@@ -722,42 +780,105 @@
);
}
- private int pullWifiBytesTransfer(
- int atomTag, @NonNull List<StatsEvent> pulledData, boolean withFgbg) {
- final NetworkTemplate template = NetworkTemplate.buildTemplateWifiWildcard();
- final NetworkStats stats = getUidNetworkStatsSinceBoot(template, withFgbg);
+ /**
+ * A data class to store a NetworkStats object with information associated to it.
+ */
+ private static class NetworkStatsExt {
+ @NonNull
+ public final NetworkStats stats;
+ public final int transport;
+ public final boolean withFgbg;
- // Return with PULL_SKIP to indicate there is an error.
- if (stats == null) return StatsManager.PULL_SKIP;
-
- addNetworkStats(atomTag, pulledData, stats, withFgbg, 0 /* ratType */);
- return StatsManager.PULL_SUCCESS;
+ NetworkStatsExt(@NonNull NetworkStats stats, int transport, boolean withFgbg) {
+ this.stats = stats;
+ this.transport = transport;
+ this.withFgbg = withFgbg;
+ }
}
- private int pullMobileBytesTransfer(
- int atomTag, @NonNull List<StatsEvent> pulledData, boolean withFgbg) {
- final NetworkTemplate template =
- NetworkTemplate.buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
- final NetworkStats stats = getUidNetworkStatsSinceBoot(template, withFgbg);
+ @NonNull
+ private List<NetworkStatsExt> collectNetworkStatsSnapshotForAtom(int atomTag) {
+ switch(atomTag) {
+ case FrameworkStatsLog.WIFI_BYTES_TRANSFER:
+ return collectUidNetworkStatsSnapshot(TRANSPORT_WIFI, /*withFgbg=*/false);
+ case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG:
+ return collectUidNetworkStatsSnapshot(TRANSPORT_WIFI, /*withFgbg=*/true);
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
+ return collectUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, /*withFgbg=*/false);
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
+ return collectUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, /*withFgbg=*/true);
+ default:
+ throw new IllegalArgumentException("Unknown atomTag " + atomTag);
+ }
+ }
- // Return with PULL_SKIP to indicate there is an error.
- if (stats == null) return StatsManager.PULL_SKIP;
+ // Get a snapshot of Uid NetworkStats. The snapshot contains NetworkStats with its associated
+ // information, and wrapped by a list since multiple NetworkStatsExt objects might be collected.
+ @NonNull
+ private List<NetworkStatsExt> collectUidNetworkStatsSnapshot(int transport, boolean withFgbg) {
+ final List<NetworkStatsExt> ret = new ArrayList<>();
+ final NetworkTemplate template = (transport == TRANSPORT_CELLULAR
+ ? NetworkTemplate.buildTemplateMobileWithRatType(
+ /*subscriptionId=*/null, NETWORK_TYPE_ALL)
+ : NetworkTemplate.buildTemplateWifiWildcard());
- addNetworkStats(atomTag, pulledData, stats, withFgbg, NETWORK_TYPE_ALL);
+ final NetworkStats stats = getUidNetworkStatsSnapshot(template, withFgbg);
+ if (stats != null) {
+ ret.add(new NetworkStatsExt(stats, transport, withFgbg));
+ }
+ return ret;
+ }
+
+
+ private int pullDataBytesTransfer(
+ int atomTag, @NonNull List<StatsEvent> pulledData) {
+ final List<NetworkStatsExt> current = collectNetworkStatsSnapshotForAtom(atomTag);
+
+ if (current == null) {
+ Slog.e(TAG, "current snapshot is null for " + atomTag + ", return.");
+ return StatsManager.PULL_SKIP;
+ }
+
+ for (final NetworkStatsExt item : current) {
+ final NetworkStatsExt baseline = CollectionUtils.find(mNetworkStatsBaselines,
+ it -> it.withFgbg == item.withFgbg && it.transport == item.transport);
+
+ // No matched baseline indicates error has occurred during initialization stage,
+ // skip reporting anything since the snapshot is invalid.
+ if (baseline == null) {
+ Slog.e(TAG, "baseline is null for " + atomTag + ", transport="
+ + item.transport + " , withFgbg=" + item.withFgbg + ", return.");
+ return StatsManager.PULL_SKIP;
+ }
+ final NetworkStatsExt diff = new NetworkStatsExt(item.stats.subtract(
+ baseline.stats).removeEmptyEntries(), item.transport, item.withFgbg);
+
+ // If no diff, skip.
+ if (diff.stats.size() == 0) continue;
+
+ addNetworkStats(atomTag, pulledData, diff);
+ }
return StatsManager.PULL_SUCCESS;
}
private void addNetworkStats(int atomTag, @NonNull List<StatsEvent> ret,
- @NonNull NetworkStats stats, boolean withFgbg, int ratType) {
- int size = stats.size();
+ @NonNull NetworkStatsExt statsExt) {
+ int size = statsExt.stats.size();
final NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
for (int j = 0; j < size; j++) {
- stats.getValues(j, entry);
+ statsExt.stats.getValues(j, entry);
StatsEvent.Builder e = StatsEvent.newBuilder();
e.setAtomId(atomTag);
+ switch (atomTag) {
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
+ e.addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true);
+ break;
+ default:
+ }
e.writeInt(entry.uid);
e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
- if (withFgbg) {
+ if (statsExt.withFgbg) {
e.writeInt(entry.set);
}
e.writeLong(entry.rxBytes);
@@ -768,14 +889,23 @@
}
}
- @Nullable private NetworkStats getUidNetworkStatsSinceBoot(
+ /**
+ * Create a snapshot of NetworkStats since boot, but add 1 bucket duration before boot as a
+ * buffer to ensure at least one full bucket will be included.
+ * Note that this should be only used to calculate diff since the snapshot might contains
+ * some traffic before boot.
+ */
+ @Nullable private NetworkStats getUidNetworkStatsSnapshot(
@NonNull NetworkTemplate template, boolean withFgbg) {
final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
+ final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(),
+ NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS);
try {
final NetworkStats stats = getNetworkStatsSession().getSummaryForAllUid(template,
- currentTimeInMillis - elapsedMillisSinceBoot, currentTimeInMillis, false);
+ currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+ currentTimeInMillis, /*includeTags=*/false);
return withFgbg ? rollupNetworkStatsByFgbg(stats) : stats.groupedByUid();
} catch (RemoteException | NullPointerException e) {
Slog.e(TAG, "Pulling netstats for " + template
@@ -3006,22 +3136,8 @@
e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
+ e.writeBoolean(mDangerousAppOpsList.contains(op.getOpCode()));
- String perm = AppOpsManager.opToPermission(op.getOpCode());
- if (perm == null) {
- e.writeBoolean(false);
- } else {
- PermissionInfo permInfo;
- try {
- permInfo = mContext.getPackageManager().getPermissionInfo(
- perm,
- 0);
- e.writeBoolean(
- permInfo.getProtection() == PROTECTION_DANGEROUS);
- } catch (PackageManager.NameNotFoundException exception) {
- e.writeBoolean(false);
- }
- }
if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
e.writeInt(mAppOpsSamplingRate);
}
@@ -3287,6 +3403,21 @@
return StatsManager.PULL_SUCCESS;
}
+ private void registerDisplayWakeStats() {
+ int tagId = FrameworkStatsLog.DISPLAY_WAKE_REASON;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ BackgroundThread.getExecutor(),
+ mStatsCallbackImpl
+ );
+ }
+
+ int pullDisplayWakeStats(int atomTag, List<StatsEvent> pulledData) {
+ //TODO: Denny, implement read/write DisplayWakeStats, b/154172964
+ return 0;
+ }
+
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 289bf66..4ba58bd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -665,12 +665,12 @@
@Override
public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, int sysUiSessionId) {
enforceBiometricDialog();
if (mBar != null) {
try {
mBar.showAuthenticationDialog(bundle, receiver, biometricModality,
- requireConfirmation, userId, opPackageName, operationId);
+ requireConfirmation, userId, opPackageName, operationId, sysUiSessionId);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 8f71943..2314afc 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -46,6 +46,8 @@
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.TvStreamConfig;
+import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -179,7 +181,7 @@
Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
return;
}
- connection.resetLocked(null, null, null, null, null);
+ connection.resetLocked(null, null, null, null, null, null);
mConnections.remove(deviceId);
buildHardwareListLocked();
TvInputHardwareInfo info = connection.getHardwareInfoLocked();
@@ -369,25 +371,34 @@
if (callback == null) {
throw new NullPointerException();
}
+ TunerResourceManager trm = (TunerResourceManager) mContext.getSystemService(
+ Context.TV_TUNER_RESOURCE_MGR_SERVICE);
synchronized (mLock) {
Connection connection = mConnections.get(deviceId);
if (connection == null) {
Slog.e(TAG, "Invalid deviceId : " + deviceId);
return null;
}
- // TODO: check with TRM to compare the client's priority with the current holder's
- // priority. If lower, do nothing.
- if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) {
- TvInputHardwareImpl hardware =
- new TvInputHardwareImpl(connection.getHardwareInfoLocked());
- try {
- callback.asBinder().linkToDeath(connection, 0);
- } catch (RemoteException e) {
- hardware.release();
- return null;
- }
- connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId);
+
+ ResourceClientProfile profile =
+ new ResourceClientProfile(tvInputSessionId, priorityHint);
+ ResourceClientProfile holderProfile = connection.getResourceClientProfileLocked();
+ if (holderProfile != null && trm != null
+ && !trm.isHigherPriority(profile, holderProfile)) {
+ Slog.d(TAG, "Acquiring does not show higher priority than the current holder."
+ + " Device id:" + deviceId);
+ return null;
}
+ TvInputHardwareImpl hardware =
+ new TvInputHardwareImpl(connection.getHardwareInfoLocked());
+ try {
+ callback.asBinder().linkToDeath(connection, 0);
+ } catch (RemoteException e) {
+ hardware.release();
+ return null;
+ }
+ connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId,
+ profile);
return connection.getHardwareLocked();
}
}
@@ -411,7 +422,7 @@
if (callback != null) {
callback.asBinder().unlinkToDeath(connection, 0);
}
- connection.resetLocked(null, null, null, null, null);
+ connection.resetLocked(null, null, null, null, null, null);
}
}
@@ -621,6 +632,7 @@
private Integer mCallingUid = null;
private Integer mResolvedUserId = null;
private Runnable mOnFirstFrameCaptured;
+ private ResourceClientProfile mResourceClientProfile = null;
public Connection(TvInputHardwareInfo hardwareInfo) {
mHardwareInfo = hardwareInfo;
@@ -629,7 +641,8 @@
// *Locked methods assume TvInputHardwareManager.mLock is held.
public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback,
- TvInputInfo info, Integer callingUid, Integer resolvedUserId) {
+ TvInputInfo info, Integer callingUid, Integer resolvedUserId,
+ ResourceClientProfile profile) {
if (mHardware != null) {
try {
mCallback.onReleased();
@@ -644,6 +657,7 @@
mCallingUid = callingUid;
mResolvedUserId = resolvedUserId;
mOnFirstFrameCaptured = null;
+ mResourceClientProfile = profile;
if (mHardware != null && mCallback != null) {
try {
@@ -698,10 +712,14 @@
return mOnFirstFrameCaptured;
}
+ public ResourceClientProfile getResourceClientProfileLocked() {
+ return mResourceClientProfile;
+ }
+
@Override
public void binderDied() {
synchronized (mLock) {
- resetLocked(null, null, null, null, null);
+ resetLocked(null, null, null, null, null, null);
}
}
@@ -713,6 +731,7 @@
+ ", mConfigs: " + Arrays.toString(mConfigs)
+ ", mCallingUid: " + mCallingUid
+ ", mResolvedUserId: " + mResolvedUserId
+ + ", mResourceClientProfile: " + mResourceClientProfile
+ " }";
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 2f70840..41aa4ee 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.media.tv.TvInputManager;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -42,6 +44,7 @@
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -71,7 +74,8 @@
@GuardedBy("mLock")
private Map<Integer, ResourcesReclaimListenerRecord> mListeners = new HashMap<>();
- private TvInputManager mManager;
+ private TvInputManager mTvInputManager;
+ private ActivityManager mActivityManager;
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
// An internal resource request count to help generate resource handle.
@@ -94,7 +98,9 @@
if (!isForTesting) {
publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService());
}
- mManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
+ mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
+ mActivityManager =
+ (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
mPriorityCongfig.parse();
}
@@ -204,7 +210,7 @@
@Override
public boolean requestDemux(@NonNull TunerDemuxRequest request,
- @NonNull int[] demuxHandle) throws RemoteException {
+ @NonNull int[] demuxHandle) throws RemoteException {
enforceTunerAccessPermission("requestDemux");
enforceTrmAccessPermission("requestDemux");
if (demuxHandle == null) {
@@ -362,14 +368,15 @@
@Override
public boolean isHigherPriority(
- ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile) {
+ ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile)
+ throws RemoteException {
enforceTrmAccessPermission("isHigherPriority");
- if (DEBUG) {
- Slog.d(TAG,
- "isHigherPriority(challengerProfile=" + challengerProfile
- + ", holderProfile=" + challengerProfile + ")");
+ if (challengerProfile == null || holderProfile == null) {
+ throw new RemoteException("Client profiles can't be null.");
}
- return true;
+ synchronized (mLock) {
+ return isHigherPriorityInternal(challengerProfile, holderProfile);
+ }
}
}
@@ -381,7 +388,7 @@
}
clientId[0] = INVALID_CLIENT_ID;
- if (mManager == null) {
+ if (mTvInputManager == null) {
Slog.e(TAG, "TvInputManager is null. Can't register client profile.");
return;
}
@@ -390,7 +397,7 @@
int pid = profile.getTvInputSessionId() == null
? Binder.getCallingPid() /*callingPid*/
- : mManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
+ : mTvInputManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
ClientProfile clientProfile = new ClientProfile.Builder(clientId[0])
.tvInputSessionId(profile.getTvInputSessionId())
@@ -693,6 +700,33 @@
}
@VisibleForTesting
+ protected boolean isHigherPriorityInternal(ResourceClientProfile challengerProfile,
+ ResourceClientProfile holderProfile) {
+ if (DEBUG) {
+ Slog.d(TAG,
+ "isHigherPriority(challengerProfile=" + challengerProfile
+ + ", holderProfile=" + challengerProfile + ")");
+ }
+ if (mTvInputManager == null) {
+ Slog.e(TAG, "TvInputManager is null. Can't compare the priority.");
+ // Allow the client to acquire the hardware interface
+ // when the TRM is not able to compare the priority.
+ return true;
+ }
+
+ int challengerPid = challengerProfile.getTvInputSessionId() == null
+ ? Binder.getCallingPid() /*callingPid*/
+ : mTvInputManager.getClientPid(challengerProfile.getTvInputSessionId()); /*tvAppId*/
+ int holderPid = holderProfile.getTvInputSessionId() == null
+ ? Binder.getCallingPid() /*callingPid*/
+ : mTvInputManager.getClientPid(holderProfile.getTvInputSessionId()); /*tvAppId*/
+
+ int challengerPriority = getClientPriority(challengerProfile.getUseCase(), challengerPid);
+ int holderPriority = getClientPriority(holderProfile.getUseCase(), holderPid);
+ return challengerPriority > holderPriority;
+ }
+
+ @VisibleForTesting
protected void releaseFrontendInternal(FrontendResource fe) {
if (DEBUG) {
Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ")");
@@ -818,8 +852,20 @@
@VisibleForTesting
protected boolean isForeground(int pid) {
- // TODO: how to get fg/bg information from pid
- return true;
+ if (mActivityManager == null) {
+ return false;
+ }
+ List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses();
+ if (appProcesses == null) {
+ return false;
+ }
+ for (RunningAppProcessInfo appProcess : appProcesses) {
+ if (appProcess.pid == pid
+ && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ return true;
+ }
+ }
+ return false;
}
private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) {
@@ -1044,7 +1090,7 @@
}
private void enforceTrmAccessPermission(String apiName) {
- getContext().enforceCallingPermission("android.permission.TUNER_RESOURCE_ACCESS",
+ getContext().enforceCallingOrSelfPermission("android.permission.TUNER_RESOURCE_ACCESS",
TAG + ": " + apiName);
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 6734ce7..72cdf4a 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -21,9 +21,8 @@
import static android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
-import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
-import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -1138,8 +1137,8 @@
targetHoldsPermission = false;
}
- final boolean basicGrant = (modeFlags & ~(FLAG_GRANT_READ_URI_PERMISSION
- | FLAG_GRANT_WRITE_URI_PERMISSION)) == 0;
+ final boolean basicGrant = (modeFlags
+ & (FLAG_GRANT_PERSISTABLE_URI_PERMISSION | FLAG_GRANT_PREFIX_URI_PERMISSION)) == 0;
if (basicGrant && targetHoldsPermission) {
// When caller holds permission, and this is a simple permission
// grant, we can skip generating any bookkeeping; when any advanced
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 63952b0..31fbaff 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2743,7 +2743,7 @@
mContext, 0,
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
- 0, null, new UserHandle(serviceUserId)));
+ PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId)));
if (!mContext.bindServiceAsUser(intent, newConn,
Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 785ca90..34998a0 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -50,7 +50,7 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Display;
-import android.view.InsetsState;
+import android.view.InsetsSource;
import android.view.MagnificationSpec;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
@@ -80,6 +80,7 @@
private final WindowManagerService mService;
+ private static final Rect EMPTY_RECT = new Rect();
private static final float[] sTempFloats = new float[9];
public AccessibilityController(WindowManagerService service) {
@@ -1166,9 +1167,9 @@
}
static Rect getNavBarInsets(DisplayContent displayContent) {
- final InsetsState insetsState =
- displayContent.getInsetsStateController().getRawInsetsState();
- return insetsState.getSource(ITYPE_NAVIGATION_BAR).getFrame();
+ final InsetsSource source = displayContent.getInsetsStateController().getRawInsetsState()
+ .peekSource(ITYPE_NAVIGATION_BAR);
+ return source != null ? source.getFrame() : EMPTY_RECT;
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f05217c..0598680 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -97,7 +97,6 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -570,7 +569,7 @@
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
- boolean mUseTransferredAnimation;
+ private boolean mUseTransferredAnimation;
/**
* @see #currentLaunchCanTurnScreenOn()
@@ -1160,8 +1159,14 @@
} else {
mLastReportedMultiWindowMode = inMultiWindowMode;
computeConfigurationAfterMultiWindowModeChange();
- ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
- true /* ignoreVisibility */);
+ // If the activity is in stopping or stopped state, for instance, it's in the
+ // split screen task and not the top one, the last configuration it should keep
+ // is the one before multi-window mode change.
+ final ActivityState state = getState();
+ if (state != STOPPED && state != STOPPING) {
+ ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
+ true /* ignoreVisibility */);
+ }
}
}
}
@@ -1281,12 +1286,6 @@
}
if (stack != null && stack.topRunningActivity() == this) {
- // carry over the PictureInPictureParams to the parent stack without calling
- // TaskOrganizerController#dispatchTaskInfoChanged.
- // this is to ensure the stack holding up-to-dated pinned stack information
- // when activity is re-parented to enter pip mode, see also
- // RootWindowContainer#moveActivityToPinnedStack
- stack.mPictureInPictureParams.copyOnlySet(pictureInPictureArgs);
// make ensure the TaskOrganizer still works after re-parenting
if (firstWindowDrawn) {
stack.setHasBeenVisible(true);
@@ -1706,7 +1705,7 @@
boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
+ boolean allowTaskSnapshot, boolean activityCreated) {
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
if (!okToDisplay()) {
@@ -1727,7 +1726,7 @@
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
- allowTaskSnapshot, activityCreated, fromRecents, snapshot);
+ allowTaskSnapshot, activityCreated, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
if (isActivityTypeHome()) {
@@ -1889,12 +1888,12 @@
private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
+ boolean allowTaskSnapshot, boolean activityCreated,
ActivityManager.TaskSnapshot snapshot) {
if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
- if (snapshotOrientationSameAsTask(snapshot) || (snapshot != null && fromRecents)) {
+ if (isSnapshotCompatible(snapshot)) {
return STARTING_WINDOW_TYPE_SNAPSHOT;
}
if (!isActivityTypeHome()) {
@@ -1906,11 +1905,22 @@
}
}
- private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) {
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ @VisibleForTesting
+ boolean isSnapshotCompatible(ActivityManager.TaskSnapshot snapshot) {
if (snapshot == null) {
return false;
}
- return task.getConfiguration().orientation == snapshot.getOrientation();
+ final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
+ final int targetRotation = rotation != ROTATION_UNDEFINED
+ // The display may rotate according to the orientation of this activity.
+ ? rotation
+ // The activity won't change display orientation.
+ : task.getWindowConfiguration().getRotation();
+ return snapshot.getRotation() == targetRotation;
}
void removeStartingWindow() {
@@ -2115,12 +2125,20 @@
@Override
boolean fillsParent() {
- return occludesParent();
+ return occludesParent(true /* includingFinishing */);
}
- /** Returns true if this activity is opaque and fills the entire space of this task. */
+ /** Returns true if this activity is not finishing, is opaque and fills the entire space of
+ * this task. */
boolean occludesParent() {
- return !finishing && mOccludesParent;
+ return occludesParent(false /* includingFinishing */);
+ }
+
+ private boolean occludesParent(boolean includingFinishing) {
+ if (!includingFinishing && finishing) {
+ return false;
+ }
+ return mOccludesParent;
}
boolean setOccludesParent(boolean occludesParent) {
@@ -2177,8 +2195,10 @@
@Override
boolean isFocusable() {
- return super.isFocusable()
- && (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable());
+ // TODO(156521483): Propagate the state down the hierarchy instead of checking the parent
+ boolean canReceiveKeys = getWindowConfiguration().canReceiveKeys()
+ && getTask().getWindowConfiguration().canReceiveKeys();
+ return super.isFocusable() && (canReceiveKeys || isAlwaysFocusable());
}
boolean isResizeable() {
@@ -3366,12 +3386,14 @@
}
setClientVisible(fromActivity.mClientVisible);
- transferAnimation(fromActivity);
+ if (fromActivity.isAnimating()) {
+ transferAnimation(fromActivity);
- // When transferring an animation, we no longer need to apply an animation to the
- // the token we transfer the animation over. Thus, set this flag to indicate we've
- // transferred the animation.
- mUseTransferredAnimation = true;
+ // When transferring an animation, we no longer need to apply an animation to
+ // the token we transfer the animation over. Thus, set this flag to indicate
+ // we've transferred the animation.
+ mUseTransferredAnimation = true;
+ }
mWmService.updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
@@ -4303,8 +4325,9 @@
* screenshot.
*/
boolean shouldUseAppThemeSnapshot() {
- return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
- true /* topToBottom */);
+ return mDisablePreviewScreenshots || forAllWindows(w -> {
+ return mWmService.isSecureLocked(w);
+ }, true /* topToBottom */);
}
/**
@@ -4775,16 +4798,7 @@
if (!task.hasChild(this)) {
throw new IllegalStateException("Activity not found in its task");
}
- final ActivityRecord activityAbove = task.getActivityAbove(this);
- if (activityAbove == null) {
- // It's the topmost activity in the task - should become resumed now
- return true;
- }
- // Check if activity above is finishing now and this one becomes the topmost in task.
- if (activityAbove.finishing) {
- return true;
- }
- return false;
+ return task.topRunningActivity() == this;
}
void handleAlreadyVisible() {
@@ -5663,11 +5677,6 @@
}
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
- showStartingWindow(prev, newTask, taskSwitch, false /* fromRecents */);
- }
-
- void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
- boolean fromRecents) {
if (mTaskOverlay) {
// We don't show starting window for overlay activities.
return;
@@ -5684,8 +5693,7 @@
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
- fromRecents);
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal());
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
@@ -6676,6 +6684,13 @@
}
@Override
+ void getAnimationPosition(Point outPosition) {
+ // Always animate from zero because if the activity doesn't fill the task, the letterbox
+ // will fill the remaining area that should be included in the animation.
+ outPosition.set(0, 0);
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newParentConfig) {
if (mCompatDisplayInsets != null) {
Configuration overrideConfig = getRequestedOverrideConfiguration();
@@ -7539,7 +7554,7 @@
if (mThumbnail != null){
mThumbnail.dumpDebug(proto, THUMBNAIL);
}
- proto.write(FILLS_PARENT, mOccludesParent);
+ proto.write(FILLS_PARENT, fillsParent());
proto.write(APP_STOPPED, mAppStopped);
proto.write(TRANSLUCENT, !occludesParent());
proto.write(VISIBLE, mVisible);
@@ -7769,6 +7784,6 @@
void setPictureInPictureParams(PictureInPictureParams p) {
pictureInPictureArgs.copyOnlySet(p);
- getTask().getRootTask().setPictureInPictureParams(p);
+ getTask().getRootTask().onPictureInPictureParamsChanged();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index db5e972..2f868d9 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -242,12 +242,6 @@
*/
boolean mInResumeTopActivity = false;
- private boolean mUpdateBoundsDeferred;
- private boolean mUpdateBoundsDeferredCalled;
- private boolean mUpdateDisplayedBoundsDeferredCalled;
- private final Rect mDeferredBounds = new Rect();
- private final Rect mDeferredDisplayedBounds = new Rect();
-
int mCurrentUser;
/** For comparison with DisplayContent bounds. */
@@ -388,6 +382,7 @@
return mBehindFullscreenActivity;
}
+ /** Returns {@code true} to stop the outer loop and indicate the result is computed. */
private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) {
if (mAboveTop) {
if (r == topActivity) {
@@ -403,7 +398,10 @@
}
if (mHandlingOccluded) {
- mHandleBehindFullscreenActivity.accept(r);
+ // Iterating through all occluded activities.
+ if (mBehindFullscreenActivity) {
+ mHandleBehindFullscreenActivity.accept(r);
+ }
} else if (r == mToCheck) {
return true;
} else if (mBehindFullscreenActivity) {
@@ -708,8 +706,10 @@
// Need to make sure windowing mode is supported. If we in the process of creating the stack
// no need to resolve the windowing mode again as it is already resolved to the right mode.
if (!creating) {
- windowingMode = taskDisplayArea.validateWindowingMode(windowingMode,
- null /* ActivityRecord */, topTask, getActivityType());
+ if (!taskDisplayArea.isValidWindowingMode(windowingMode, null /* ActivityRecord */,
+ topTask, getActivityType())) {
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ }
}
if (taskDisplayArea.getRootSplitScreenPrimaryTask() == this
&& windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
@@ -846,58 +846,6 @@
return getDisplayContent();
}
- /**
- * Defers updating the bounds of the stack. If the stack was resized/repositioned while
- * deferring, the bounds will update in {@link #continueUpdateBounds()}.
- */
- void deferUpdateBounds() {
- if (!mUpdateBoundsDeferred) {
- mUpdateBoundsDeferred = true;
- mUpdateBoundsDeferredCalled = false;
- }
- }
-
- /**
- * Continues updating bounds after updates have been deferred. If there was a resize attempt
- * between {@link #deferUpdateBounds()} and {@link #continueUpdateBounds()}, the stack will
- * be resized to that bounds.
- */
- void continueUpdateBounds() {
- if (mUpdateBoundsDeferred) {
- mUpdateBoundsDeferred = false;
- if (mUpdateBoundsDeferredCalled) {
- setTaskBounds(mDeferredBounds);
- setBounds(mDeferredBounds);
- }
- }
- }
-
- private boolean updateBoundsAllowed(Rect bounds) {
- if (!mUpdateBoundsDeferred) {
- return true;
- }
- if (bounds != null) {
- mDeferredBounds.set(bounds);
- } else {
- mDeferredBounds.setEmpty();
- }
- mUpdateBoundsDeferredCalled = true;
- return false;
- }
-
- private boolean updateDisplayedBoundsAllowed(Rect bounds) {
- if (!mUpdateBoundsDeferred) {
- return true;
- }
- if (bounds != null) {
- mDeferredDisplayedBounds.set(bounds);
- } else {
- mDeferredDisplayedBounds.setEmpty();
- }
- mUpdateDisplayedBoundsDeferredCalled = true;
- return false;
- }
-
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
final DisplayContent display = getDisplay();
@@ -1334,6 +1282,8 @@
prev.cpuTimeAtResume = 0; // reset it
}
+ mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
+
// Notify when the task stack has changed, but only if visibilities changed (not just
// focus). Also if there is an active pinned stack - we always want to notify it about
// task stack changes, because its positioning may depend on it.
@@ -1342,8 +1292,6 @@
mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
-
- mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
}
boolean isTopStackInDisplayArea() {
@@ -1363,8 +1311,17 @@
/**
* Make sure that all activities that need to be visible in the stack (that is, they
* currently can be seen by the user) actually are and update their configuration.
+ * @param starting The top most activity in the task.
+ * The activity is either starting or resuming.
+ * Caller should ensure starting activity is visible.
+ * @param preserveWindows Flag indicating whether windows should be preserved when updating
+ * configuration in {@link mEnsureActivitiesVisibleHelper}.
+ * @param configChanges Parts of the configuration that changed for this activity for evaluating
+ * if the screen should be frozen as part of
+ * {@link mEnsureActivitiesVisibleHelper}.
+ *
*/
- void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+ void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
boolean preserveWindows) {
ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
}
@@ -1373,9 +1330,19 @@
* Ensure visibility with an option to also update the configuration of visible activities.
* @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
* @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
+ * @param starting The top most activity in the task.
+ * The activity is either starting or resuming.
+ * Caller should ensure starting activity is visible.
+ * @param notifyClients Flag indicating whether the visibility updates should be sent to the
+ * clients in {@link mEnsureActivitiesVisibleHelper}.
+ * @param preserveWindows Flag indicating whether windows should be preserved when updating
+ * configuration in {@link mEnsureActivitiesVisibleHelper}.
+ * @param configChanges Parts of the configuration that changed for this activity for evaluating
+ * if the screen should be frozen as part of
+ * {@link mEnsureActivitiesVisibleHelper}.
*/
// TODO: Should be re-worked based on the fact that each task as a stack in most cases.
- void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+ void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
mTopActivityOccludesKeyguard = false;
mTopDismissingKeyguardActivity = null;
@@ -2687,10 +2654,6 @@
// TODO: Can only be called from special methods in ActivityStackSupervisor.
// Need to consolidate those calls points into this resize method so anyone can call directly.
void resize(Rect displayedBounds, boolean preserveWindows, boolean deferResume) {
- if (!updateBoundsAllowed(displayedBounds)) {
- return;
- }
-
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + getRootTaskId());
mAtmService.deferWindowLayout();
try {
@@ -2730,10 +2693,6 @@
* basically resizes both stack and task bounds to the same bounds.
*/
private void setTaskBounds(Rect bounds) {
- if (!updateBoundsAllowed(bounds)) {
- return;
- }
-
final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds,
PooledLambda.__(Task.class), bounds);
forAllLeafTasks(c, true /* traverseTopToBottom */);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index ed21539..62979ff 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -69,7 +69,6 @@
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_ONLY;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.RootWindowContainer.TAG_STATES;
@@ -125,7 +124,6 @@
import android.os.WorkSource;
import android.provider.MediaStore;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
@@ -364,11 +362,6 @@
*/
boolean mAppVisibilitiesChangedSinceLastPause;
- /**
- * Set of tasks that are in resizing mode during an app transition to fill the "void".
- */
- private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>();
-
private KeyguardController mKeyguardController;
private PowerManager mPowerManager;
@@ -849,7 +842,7 @@
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
- r.assistToken));
+ r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
@@ -1415,29 +1408,6 @@
return mLaunchParamsController;
}
- private void deferUpdateRecentsHomeStackBounds() {
- mRootWindowContainer.deferUpdateBounds(ACTIVITY_TYPE_RECENTS);
- mRootWindowContainer.deferUpdateBounds(ACTIVITY_TYPE_HOME);
- }
-
- private void continueUpdateRecentsHomeStackBounds() {
- mRootWindowContainer.continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
- mRootWindowContainer.continueUpdateBounds(ACTIVITY_TYPE_HOME);
- }
-
- void notifyAppTransitionDone() {
- continueUpdateRecentsHomeStackBounds();
- for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
- final int taskId = mResizingTasksDuringAnimation.valueAt(i);
- final Task task =
- mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY);
- if (task != null) {
- task.setTaskDockedResizing(false);
- }
- }
- mResizingTasksDuringAnimation.clear();
- }
-
void setSplitScreenResizing(boolean resizing) {
if (resizing == mDockedStackResizing) {
return;
@@ -1470,6 +1440,7 @@
mService.deferWindowLayout();
try {
stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ stack.setBounds(null);
if (toDisplay.getDisplayId() != stack.getDisplayId()) {
stack.reparent(toDisplay.getDefaultTaskDisplayArea(), false /* onTop */);
} else {
@@ -2471,16 +2442,6 @@
}
}
- /**
- * Puts a task into resizing mode during the next app transition.
- *
- * @param task The task to put into resizing mode
- */
- void setResizingDuringAnimation(Task task) {
- mResizingTasksDuringAnimation.add(task.mTaskId);
- task.setTaskDockedResizing(true);
- }
-
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
Task task = null;
@@ -2508,27 +2469,12 @@
mService.deferWindowLayout();
try {
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // Defer updating the stack in which recents is until the app transition is done, to
- // not run into issues where we still need to draw the task in recents but the
- // docked stack is already created.
- deferUpdateRecentsHomeStackBounds();
- // TODO(task-hierarchy): Remove when tiles are in hierarchy.
- // Unset launching windowing mode to prevent creating split-screen-primary stack
- // in RWC#anyTaskForId() below.
- activityOptions.setLaunchWindowingMode(WINDOWING_MODE_UNDEFINED);
- }
-
task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
if (task == null) {
- continueUpdateRecentsHomeStackBounds();
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
- } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- && task.getWindowingMode() != windowingMode) {
- mService.moveTaskToSplitScreenPrimaryTask(task, true /* toTop */);
}
if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
@@ -2552,7 +2498,7 @@
mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
- task.mTaskId, 0, options, true /* fromRecents */);
+ task.mTaskId, 0, options);
// Apply options to prevent pendingOptions be taken by client to make sure
// the override pending app transition will be applied immediately.
targetActivity.applyOptionsLocked();
@@ -2577,12 +2523,6 @@
false /* validateIncomingUser */, null /* originatingPendingIntent */,
false /* allowBackgroundActivityStart */);
} finally {
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
- // If we are launching the task in the docked stack, put it into resizing mode so
- // the window renders full-screen with the background filling the void. Also only
- // call this at the end to make sure that tasks exists on the window manager side.
- setResizingDuringAnimation(task);
- }
mService.continueWindowLayout();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 79e8ee3..bcdd6e3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1539,7 +1539,10 @@
*
* Note: This method should only be called from {@link #startActivityUnchecked}.
*/
- private int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
+
+ // TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
+ @VisibleForTesting
+ int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity) {
@@ -1660,7 +1663,10 @@
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
- mTargetStack.ensureActivitiesVisible(mStartActivity, 0, !PRESERVE_WINDOWS);
+ // Passing {@code null} as the start parameter ensures all activities are made
+ // visible.
+ mTargetStack.ensureActivitiesVisible(null /* starting */,
+ 0 /* configChanges */, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 4181f4b..d5df906 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -152,17 +152,6 @@
IVoiceInteractor mInteractor);
/**
- * Callback for window manager to let activity manager know that the app transition was
- * cancelled.
- */
- public abstract void notifyAppTransitionCancelled();
-
- /**
- * Callback for window manager to let activity manager know that the app transition is finished.
- */
- public abstract void notifyAppTransitionFinished();
-
- /**
* Returns the top activity from each of the currently visible stacks. The first entry will be
* the focused activity.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 6a8d5d9..fdbb2b2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2476,13 +2476,12 @@
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
synchronized (mGlobalLock) {
moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
- SafeActivityOptions.fromBundle(bOptions), false /* fromRecents */);
+ SafeActivityOptions.fromBundle(bOptions));
}
}
void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
- @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
- boolean fromRecents) {
+ @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
assertPackageMatchesCallingUid(callingPackage);
@@ -2527,7 +2526,7 @@
// We are reshowing a task, use a starting window to hide the initial draw delay
// so the transition can start earlier.
topActivity.showStartingWindow(null /* prev */, false /* newTask */,
- true /* taskSwitch */, fromRecents);
+ true /* taskSwitch */);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -3213,7 +3212,7 @@
if (TextUtils.equals(pae.intent.getAction(),
android.service.voice.VoiceInteractionService.SERVICE_INTERFACE)) {
// Start voice interaction through VoiceInteractionManagerService.
- mAssistUtils.showSessionForActiveService(sendBundle, SHOW_SOURCE_APPLICATION,
+ mAssistUtils.showSessionForActiveService(pae.extras, SHOW_SOURCE_APPLICATION,
null, null);
} else {
pae.intent.replaceExtras(pae.extras);
@@ -3320,7 +3319,7 @@
}
@Override
- public void resizeTask(int taskId, Rect bounds, int resizeMode) {
+ public boolean resizeTask(int taskId, Rect bounds, int resizeMode) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
long ident = Binder.clearCallingIdentity();
try {
@@ -3329,10 +3328,11 @@
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
- return;
+ return false;
}
if (!task.getWindowConfiguration().canResizeTask()) {
- throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
+ Slog.w(TAG, "resizeTask not allowed on task=" + task);
+ return false;
}
// Reparent the task to the right stack if necessary
@@ -3340,7 +3340,7 @@
// After reparenting (which only resizes the task to the stack bounds), resize the
// task to the actual bounds provided
- task.resize(bounds, resizeMode, preserveWindow, !DEFER_RESUME);
+ return task.resize(bounds, resizeMode, preserveWindow);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -6079,20 +6079,6 @@
}
@Override
- public void notifyAppTransitionFinished() {
- synchronized (mGlobalLock) {
- mStackSupervisor.notifyAppTransitionDone();
- }
- }
-
- @Override
- public void notifyAppTransitionCancelled() {
- synchronized (mGlobalLock) {
- mStackSupervisor.notifyAppTransitionDone();
- }
- }
-
- @Override
public List<IBinder> getTopVisibleActivities() {
synchronized (mGlobalLock) {
return mRootWindowContainer.getTopVisibleActivities();
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 0519b80..529c4f6 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -85,4 +85,25 @@
}
void dumpDebug(ProtoOutputStream proto);
+
+ /**
+ * Gets called when the animation is about to finish and gives the client the opportunity to
+ * defer finishing the animation, i.e. it keeps the leash around until the client calls
+ * endDeferFinishCallback.
+ * <p>
+ * This has the same effect as
+ * {@link com.android.server.wm.SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)}
+ * . The later will be evaluated first and has precedence over this method if it returns true,
+ * which means that if the {@link com.android.server.wm.SurfaceAnimator.Animatable} requests to
+ * defer its finish, this method won't be called so this adapter will never have access to the
+ * finish callback. On the other hand, if the
+ * {@link com.android.server.wm.SurfaceAnimator.Animatable}, doesn't request to defer, this
+ * {@link AnimationAdapter} is responsible for ending the animation.
+ *
+ * @param endDeferFinishCallback The callback to call when defer finishing should be ended.
+ * @return Whether the client would like to defer the animation finish.
+ */
+ default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 654ccc8..67fe968 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -166,19 +166,13 @@
// done behind a dream window.
final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
- final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
- final ActivityRecord animLpActivity = allowAnimations
- ? findAnimLayoutParamsToken(transit, activityTypes)
- : null;
- final ActivityRecord topOpeningApp = allowAnimations
- ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
- : null;
- final ActivityRecord topClosingApp = allowAnimations
- ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
- : null;
- final ActivityRecord topChangingApp = allowAnimations
- ? getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */)
- : null;
+ final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
+ final ActivityRecord topOpeningApp =
+ getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
+ final ActivityRecord topClosingApp =
+ getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
+ final ActivityRecord topChangingApp =
+ getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 345cfb0..a45a15b 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -66,6 +66,7 @@
final int mFeatureId;
private final DisplayAreaOrganizerController mOrganizerController;
IDisplayAreaOrganizer mOrganizer;
+ private final Configuration mTmpConfiguration = new Configuration();
DisplayArea(WindowManagerService wms, Type type, String name) {
this(wms, type, name, FEATURE_UNDEFINED);
@@ -162,8 +163,10 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ mTmpConfiguration.setTo(getConfiguration());
super.onConfigurationChanged(newParentConfig);
- if (mOrganizer != null) {
+
+ if (mOrganizer != null && getConfiguration().diff(mTmpConfiguration) != 0) {
mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 23d4cc3..85c439c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -54,7 +54,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -236,7 +235,6 @@
implements WindowManagerPolicy.DisplayContentInfo {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
- private static final int NO_ROTATION = -1;
/** The default scaling mode that scales content automatically. */
static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -500,6 +498,8 @@
*/
ActivityRecord mFixedRotationLaunchingApp;
+ FixedRotationAnimationController mFixedRotationAnimationController;
+
final FixedRotationTransitionListener mFixedRotationTransitionListener =
new FixedRotationTransitionListener();
@@ -1393,36 +1393,40 @@
final WindowContainer orientationSource = getLastOrientationSource();
final ActivityRecord r =
orientationSource != null ? orientationSource.asActivityRecord() : null;
- if (r != null && r.getTask() != null
- && orientation != r.getTask().mLastReportedRequestedOrientation) {
+ if (r != null) {
final Task task = r.getTask();
- task.mLastReportedRequestedOrientation = orientation;
- mAtmService.getTaskChangeNotificationController()
- .notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
- }
- // Currently there is no use case from non-activity.
- if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
- // Display orientation should be deferred until the top fixed rotation is finished.
- return false;
+ if (task != null && orientation != task.mLastReportedRequestedOrientation) {
+ task.mLastReportedRequestedOrientation = orientation;
+ mAtmService.getTaskChangeNotificationController()
+ .notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
+ }
+ // Currently there is no use case from non-activity.
+ if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
+ // Display orientation should be deferred until the top fixed rotation is finished.
+ return false;
+ }
}
return mDisplayRotation.updateOrientation(orientation, forceUpdate);
}
- /** @return a valid rotation if the activity can use different orientation than the display. */
+ /**
+ * Returns a valid rotation if the activity can use different orientation than the display.
+ * Otherwise {@link #ROTATION_UNDEFINED}.
+ */
@Surface.Rotation
- private int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
+ int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
if (!mWmService.mIsFixedRotationTransformEnabled) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
if (r.inMultiWindowMode()
|| r.getRequestedConfigurationOrientation() == getConfiguration().orientation) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
final int currentRotation = getRotation();
final int rotation = mDisplayRotation.rotationForOrientation(r.getRequestedOrientation(),
currentRotation);
if (rotation == currentRotation) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
return rotation;
}
@@ -1432,9 +1436,13 @@
* is launching until the launch animation is done to avoid showing the previous activity
* inadvertently in a wrong orientation.
*
+ * @param r The launching activity which may change display orientation.
+ * @param checkOpening Whether to check if the activity is animating by transition. Set to
+ * {@code true} if the caller is not sure whether the activity is launching.
* @return {@code true} if the fixed rotation is started.
*/
- private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r) {
+ boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
+ boolean checkOpening) {
if (!mWmService.mIsFixedRotationTransformEnabled) {
return false;
}
@@ -1445,19 +1453,18 @@
// It has been set and not yet finished.
return true;
}
- if (!mAppTransition.isTransitionSet()) {
- // Apply normal rotation animation in case of the activity set different requested
- // orientation without activity switch.
- return false;
- }
- if (!mOpeningApps.contains(r)
- // Without screen rotation, the rotation behavior of non-top visible activities is
- // undefined. So the fixed rotated activity needs to cover the screen.
- && r.findMainWindow() != mDisplayPolicy.getTopFullscreenOpaqueWindow()) {
+ if (checkOpening) {
+ if (!mAppTransition.isTransitionSet() && !mOpeningApps.contains(r)) {
+ // Apply normal rotation animation in case of the activity set different requested
+ // orientation without activity switch.
+ return false;
+ }
+ } else if (r != topRunningActivity()) {
+ // If the transition has not started yet, the activity must be the top.
return false;
}
final int rotation = rotationForActivityInDifferentOrientation(r);
- if (rotation == NO_ROTATION) {
+ if (rotation == ROTATION_UNDEFINED) {
return false;
}
if (!r.getParent().matchParentBounds()) {
@@ -1510,6 +1517,10 @@
sendNewConfiguration();
return;
}
+ if (mDisplayRotation.isWaitingForRemoteRotation()) {
+ // There is pending rotation change to apply.
+ return;
+ }
// The orientation of display is not changed.
clearFixedRotationLaunchingApp();
}
@@ -1529,6 +1540,11 @@
}
private void startFixedRotationTransform(WindowToken token, int rotation) {
+ if (mFixedRotationAnimationController == null) {
+ mFixedRotationAnimationController = new FixedRotationAnimationController(
+ this);
+ }
+ mFixedRotationAnimationController.hide(rotation);
mTmpConfiguration.unset();
final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
@@ -1545,11 +1561,18 @@
*/
void rotateInDifferentOrientationIfNeeded(ActivityRecord activityRecord) {
int rotation = rotationForActivityInDifferentOrientation(activityRecord);
- if (rotation != NO_ROTATION) {
+ if (rotation != ROTATION_UNDEFINED) {
startFixedRotationTransform(activityRecord, rotation);
}
}
+ void finishFixedRotationAnimation() {
+ if (mFixedRotationAnimationController != null
+ && mFixedRotationAnimationController.show()) {
+ mFixedRotationAnimationController = null;
+ }
+ }
+
/**
* Update rotation of the display.
*
@@ -1620,9 +1643,7 @@
}
}
- // Announce rotation only if we will not animate as we already have the
- // windows in final state. Otherwise, we make this call at the rotation end.
- if (screenRotationAnimation == null && mWmService.mAccessibilityController != null) {
+ if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onRotationChangedLocked(this);
}
}
@@ -2547,6 +2568,9 @@
}
for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
final WindowState win = mTapExcludedWindows.get(i);
+ if (!win.isVisibleLw()) {
+ continue;
+ }
win.getTouchableRegion(mTmpRegion);
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
@@ -3293,7 +3317,7 @@
mInputMethodWindow.getDisplayId());
}
mInsetsStateController.getSourceProvider(ITYPE_IME).setWindow(win,
- null /* frameProvider */, null /* imeFrameProvider */);
+ mDisplayPolicy.getImeSourceFrameProvider(), null /* imeFrameProvider */);
computeImeTarget(true /* updateImeTarget */);
updateImeControlTarget();
}
@@ -3704,8 +3728,7 @@
}
boolean hasSecureWindowOnScreen() {
- final WindowState win = getWindow(
- w -> w.isOnScreen() && (w.mAttrs.flags & FLAG_SECURE) != 0);
+ final WindowState win = getWindow(w -> w.isOnScreen() && mWmService.isSecureLocked(w));
return win != null;
}
@@ -5530,7 +5553,7 @@
/**
* The animating activity which shows the recents task list. It is set between
* {@link RecentsAnimationController#initialize} and
- * {@link RecentsAnimationController#cancelAnimation}.
+ * {@link RecentsAnimationController#cleanupAnimation}.
*/
private ActivityRecord mAnimatingRecents;
@@ -5553,14 +5576,25 @@
* 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() {
+ void onFinishRecentsAnimation(boolean moveRecentsToBack) {
final ActivityRecord animatingRecents = mAnimatingRecents;
mAnimatingRecents = null;
- if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp
- && !animatingRecents.hasFixedRotationTransform()) {
- // The recents activity won't be the top, such as giving up the swipe up gesture
- // and return to the original top.
+ if (!moveRecentsToBack) {
+ // 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;
+ }
+
+ if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) {
+ // Because it won't affect display orientation, just finish the transform.
+ animatingRecents.finishFixedRotationTransform();
mFixedRotationLaunchingApp = null;
+ } else {
+ // If there is already a launching activity that is not the recents, before its
+ // transition is completed, the recents animation may be started. So if the recents
+ // activity won't be the top, the display orientation should be updated according
+ // to the current top activity.
+ continueUpdateOrientationForDiffOrienLaunchingApp();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 541be0a..2f18a0d 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -95,6 +95,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
@@ -873,10 +874,6 @@
}
break;
- case TYPE_SCREENSHOT:
- attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- break;
-
case TYPE_TOAST:
// While apps should use the dedicated toast APIs to add such windows
// it possible legacy apps to add the window directly. Therefore, we
@@ -996,6 +993,11 @@
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
break;
+ case TYPE_TRUSTED_APPLICATION_OVERLAY:
+ mContext.enforcePermission(
+ android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
+ "DisplayPolicy");
+ break;
case TYPE_STATUS_BAR_PANEL:
return WindowManagerGlobal.ADD_INVALID_TYPE;
}
@@ -1104,6 +1106,24 @@
}
}
+ TriConsumer<DisplayFrames, WindowState, Rect> getImeSourceFrameProvider() {
+ return (displayFrames, windowState, inOutFrame) -> {
+ if (mNavigationBar != null && navigationBarPosition(displayFrames.mDisplayWidth,
+ displayFrames.mDisplayHeight,
+ displayFrames.mRotation) == NAV_BAR_BOTTOM) {
+ // In gesture navigation, nav bar frame is larger than frame to calculate insets.
+ // IME should not provide frame which is smaller than the nav bar frame. Otherwise,
+ // nav bar might be overlapped with the content of the client when IME is shown.
+ sTmpRect.set(inOutFrame);
+ sTmpRect.intersectUnchecked(mNavigationBar.getFrameLw());
+ inOutFrame.inset(windowState.getGivenContentInsetsLw());
+ inOutFrame.union(sTmpRect);
+ } else {
+ inOutFrame.inset(windowState.getGivenContentInsetsLw());
+ }
+ };
+ }
+
private static void enforceSingleInsetsTypeCorrespondingToWindowType(int[] insetsTypes) {
int count = 0;
for (int insetsType : insetsTypes) {
@@ -2030,9 +2050,13 @@
final Rect dfu = displayFrames.mUnrestricted;
Insets insets = Insets.of(0, 0, 0, 0);
for (int i = types.size() - 1; i >= 0; i--) {
- insets = Insets.max(insets, mDisplayContent.getInsetsPolicy()
- .getInsetsForDispatch(win).getSource(types.valueAt(i))
- .calculateInsets(dfu, attrs.isFitInsetsIgnoringVisibility()));
+ final InsetsSource source = mDisplayContent.getInsetsPolicy()
+ .getInsetsForDispatch(win).peekSource(types.valueAt(i));
+ if (source == null) {
+ continue;
+ }
+ insets = Insets.max(insets, source.calculateInsets(
+ dfu, attrs.isFitInsetsIgnoringVisibility()));
}
final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
@@ -3154,16 +3178,6 @@
return 0;
}
- /**
- * Return true if it is okay to perform animations for an app transition
- * that is about to occur. You may return false for this if, for example,
- * the dream window is currently displayed so the switch should happen
- * immediately.
- */
- public boolean allowAppAnimationsLw() {
- return !mShowingDream;
- }
-
private void requestTransientBars(WindowState swipeTarget) {
if (!mService.mPolicy.isUserSetupComplete()) {
// Swipe-up for navigation bar is disabled during setup
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index ebfe70c..c3f9061 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -560,6 +560,7 @@
}, true /* traverseTopToBottom */);
mSeamlessRotationCount = 0;
mRotatingSeamlessly = false;
+ mDisplayContent.finishFixedRotationAnimation();
}
private void prepareSeamlessRotation() {
@@ -646,6 +647,7 @@
"Performing post-rotate rotation after seamless rotation");
// Finish seamless rotation.
mRotatingSeamlessly = false;
+ mDisplayContent.finishFixedRotationAnimation();
updateRotationAndSendNewConfigIfChanged();
}
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 484a5a8..5a24847 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -28,6 +28,7 @@
import android.util.Slog;
import android.view.IWindow;
import android.view.InputApplicationHandle;
+import android.view.InputChannel;
/**
* Keeps track of embedded windows.
@@ -95,7 +96,7 @@
void remove(IWindow client) {
for (int i = mWindows.size() - 1; i >= 0; i--) {
if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) {
- mWindows.removeAt(i);
+ mWindows.removeAt(i).onRemoved();
return;
}
}
@@ -104,7 +105,7 @@
void onWindowRemoved(WindowState host) {
for (int i = mWindows.size() - 1; i >= 0; i--) {
if (mWindows.valueAt(i).mHostWindowState == host) {
- mWindows.removeAt(i);
+ mWindows.removeAt(i).onRemoved();
}
}
}
@@ -132,6 +133,9 @@
@Nullable final ActivityRecord mHostActivityRecord;
final int mOwnerUid;
final int mOwnerPid;
+ final WindowManagerService mWmService;
+ InputChannel mInputChannel;
+ final int mWindowType;
/**
* @param clientToken client token used to clean up the map if the embedding process dies
@@ -142,14 +146,16 @@
* @param ownerUid calling uid
* @param ownerPid calling pid used for anr blaming
*/
- EmbeddedWindow(IWindow clientToken, WindowState hostWindowState, int ownerUid,
- int ownerPid) {
+ EmbeddedWindow(WindowManagerService service, IWindow clientToken,
+ WindowState hostWindowState, int ownerUid, int ownerPid, int windowType) {
+ mWmService = service;
mClient = clientToken;
mHostWindowState = hostWindowState;
mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
: null;
mOwnerUid = ownerUid;
mOwnerPid = ownerPid;
+ mWindowType = windowType;
}
String getName() {
@@ -167,5 +173,29 @@
return new InputApplicationHandle(
mHostWindowState.mInputWindowHandle.inputApplicationHandle);
}
+
+ InputChannel openInputChannel() {
+ final String name = getName();
+
+ final InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
+ mInputChannel = inputChannels[0];
+ final InputChannel clientChannel = inputChannels[1];
+ mWmService.mInputManager.registerInputChannel(mInputChannel);
+
+ if (mInputChannel.getToken() != clientChannel.getToken()) {
+ throw new IllegalStateException("Client and Server tokens are expected to"
+ + "be the same");
+ }
+
+ return clientChannel;
+ }
+
+ void onRemoved() {
+ if (mInputChannel != null) {
+ mWmService.mInputManager.unregisterInputChannel(mInputChannel);
+ mInputChannel.dispose();
+ mInputChannel = null;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index c92de2b..c4e03f5 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -21,6 +21,7 @@
import static com.android.server.wm.ActivityStack.TAG_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
+import android.annotation.Nullable;
import android.util.Slog;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -42,6 +43,16 @@
mContiner = container;
}
+ /**
+ * Update all attributes except {@link mContiner} to use in subsequent calculations.
+ *
+ * @param starting The activity that is being started
+ * @param configChanges Parts of the configuration that changed for this activity for evaluating
+ * if the screen should be frozen.
+ * @param preserveWindows Flag indicating whether windows should be preserved when updating.
+ * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
+ * be sent to the clients.
+ */
void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
boolean notifyClients) {
mStarting = starting;
@@ -60,8 +71,17 @@
* Ensure visibility with an option to also update the configuration of visible activities.
* @see ActivityStack#ensureActivitiesVisible(ActivityRecord, int, boolean)
* @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
+ * @param starting The top most activity in the task.
+ * The activity is either starting or resuming.
+ * Caller should ensure starting activity is visible.
+ *
+ * @param configChanges Parts of the configuration that changed for this activity for evaluating
+ * if the screen should be frozen.
+ * @param preserveWindows Flag indicating whether windows should be preserved when updating.
+ * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
+ * be sent to the clients.
*/
- void process(ActivityRecord starting, int configChanges, boolean preserveWindows,
+ void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
boolean notifyClients) {
reset(starting, configChanges, preserveWindows, notifyClients);
diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
new file mode 100644
index 0000000..7aca637
--- /dev/null
+++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
@@ -0,0 +1,197 @@
+/*
+ * 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;
+
+import static com.android.server.wm.AnimationSpecProto.WINDOW;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
+import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
+
+import android.content.res.Configuration;
+import android.util.proto.ProtoOutputStream;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
+
+import com.android.internal.R;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controller to fade out and in system ui when applying a fixed rotation transform to a window
+ * token.
+ *
+ * The system bars will be fade out when the fixed rotation transform starts and will be fade in
+ * once all surfaces have been rotated.
+ */
+public class FixedRotationAnimationController {
+
+ private final WindowManagerService mWmService;
+ private boolean mShowRequested = true;
+ private int mTargetRotation = Configuration.ORIENTATION_UNDEFINED;
+ private final ArrayList<WindowState> mAnimatedWindowStates = new ArrayList<>(2);
+ private final Runnable[] mDeferredFinishCallbacks;
+
+ public FixedRotationAnimationController(DisplayContent displayContent) {
+ mWmService = displayContent.mWmService;
+ addAnimatedWindow(displayContent.getDisplayPolicy().getStatusBar());
+ addAnimatedWindow(displayContent.getDisplayPolicy().getNavigationBar());
+ mDeferredFinishCallbacks = new Runnable[mAnimatedWindowStates.size()];
+ }
+
+ private void addAnimatedWindow(WindowState windowState) {
+ if (windowState != null) {
+ mAnimatedWindowStates.add(windowState);
+ }
+ }
+
+ /**
+ * Show the previously hidden {@link WindowToken} if their surfaces have already been rotated.
+ *
+ * @return True if the show animation has been started, in which case the caller no longer needs
+ * this {@link FixedRotationAnimationController}.
+ */
+ boolean show() {
+ if (!mShowRequested && readyToShow()) {
+ mShowRequested = true;
+ for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
+ WindowState windowState = mAnimatedWindowStates.get(i);
+ fadeWindowToken(true, windowState.getParent(), i);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void hide(int targetRotation) {
+ mTargetRotation = targetRotation;
+ if (mShowRequested) {
+ mShowRequested = false;
+ for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
+ WindowState windowState = mAnimatedWindowStates.get(i);
+ fadeWindowToken(false /* show */, windowState.getParent(), i);
+ }
+ }
+ }
+
+ void cancel() {
+ for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
+ WindowState windowState = mAnimatedWindowStates.get(i);
+ mShowRequested = true;
+ fadeWindowToken(true /* show */, windowState.getParent(), i);
+ }
+ }
+
+ private void fadeWindowToken(boolean show, WindowContainer<WindowToken> windowToken,
+ int index) {
+ Animation animation = AnimationUtils.loadAnimation(mWmService.mContext,
+ show ? R.anim.fade_in : R.anim.fade_out);
+ LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation);
+
+ FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter(
+ windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, index);
+
+ // We deferred the end of the animation when hiding the token, so we need to end it now that
+ // it's shown again.
+ SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
+ if (mDeferredFinishCallbacks[index] != null) {
+ mDeferredFinishCallbacks[index].run();
+ mDeferredFinishCallbacks[index] = null;
+ }
+ } : null;
+ windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
+ mShowRequested, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback);
+ }
+
+ /**
+ * Check if all the mAnimatedWindowState's surfaces have been rotated to the
+ * mTargetRotation.
+ */
+ private boolean readyToShow() {
+ for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
+ WindowState windowState = mAnimatedWindowStates.get(i);
+ if (windowState.getConfiguration().windowConfiguration.getRotation()
+ != mTargetRotation || windowState.mPendingSeamlessRotate != null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) {
+ return new LocalAnimationAdapter.AnimationSpec() {
+
+ Transformation mTransformation = new Transformation();
+
+ @Override
+ public boolean getShowWallpaper() {
+ return true;
+ }
+
+ @Override
+ public long getDuration() {
+ return animation.getDuration();
+ }
+
+ @Override
+ public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
+ long currentPlayTime) {
+ mTransformation.clear();
+ animation.getTransformation(currentPlayTime, mTransformation);
+ t.setAlpha(leash, mTransformation.getAlpha());
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.println(animation);
+ }
+
+ @Override
+ public void dumpDebugInner(ProtoOutputStream proto) {
+ final long token = proto.start(WINDOW);
+ proto.write(ANIMATION, animation.toString());
+ proto.end(token);
+ }
+ };
+ }
+
+ private class FixedRotationAnimationAdapter extends LocalAnimationAdapter {
+ private final boolean mShow;
+ private final int mIndex;
+
+ FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec,
+ SurfaceAnimationRunner surfaceAnimationRunner, boolean show, int index) {
+ super(windowAnimationSpec, surfaceAnimationRunner);
+ mShow = show;
+ mIndex = index;
+ }
+
+ @Override
+ public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ // We defer the end of the hide animation to ensure the tokens stay hidden until
+ // we show them again.
+ if (!mShow) {
+ mDeferredFinishCallbacks[mIndex] = endDeferFinishCallback;
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 1b1898b..efcd61d 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -469,8 +469,12 @@
public void accept(WindowState w) {
final InputChannel inputChannel = w.mInputChannel;
final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
+ final RecentsAnimationController recentsAnimationController =
+ mService.getRecentsAnimationController();
+ final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
+ && recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
- || w.cantReceiveTouchInput()) {
+ || (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
mInputTransaction.setInputWindowInfo(
w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
@@ -486,22 +490,16 @@
final boolean hasFocus = w.isFocused();
final boolean isVisible = w.isVisibleLw();
- if (mAddRecentsAnimationInputConsumerHandle) {
- final RecentsAnimationController recentsAnimationController =
- mService.getRecentsAnimationController();
- if (recentsAnimationController != null
- && recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord)) {
- if (recentsAnimationController.updateInputConsumerForApp(
- mRecentsAnimationInputConsumer.mWindowHandle, hasFocus)) {
- mRecentsAnimationInputConsumer.show(mInputTransaction, w);
- mAddRecentsAnimationInputConsumerHandle = false;
- }
+ if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
+ if (recentsAnimationController.updateInputConsumerForApp(
+ mRecentsAnimationInputConsumer.mWindowHandle, hasFocus)) {
+ mRecentsAnimationInputConsumer.show(mInputTransaction, w);
+ mAddRecentsAnimationInputConsumerHandle = false;
}
}
if (w.inPinnedWindowingMode()) {
if (mAddPipInputConsumerHandle) {
-
final Task rootTask = w.getTask().getRootTask();
mPipInputConsumer.mWindowHandle.replaceTouchableRegionWithCrop(
rootTask.getSurfaceControl());
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 317bb43..d02be88 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -60,7 +60,37 @@
private final IntArray mShowingTransientTypes = new IntArray();
/** For resetting visibilities of insets sources. */
- private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() { };
+ private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() {
+
+ @Override
+ public void notifyInsetsControlChanged() {
+ boolean hasLeash = false;
+ final InsetsSourceControl[] controls =
+ mStateController.getControlsForDispatch(this);
+ if (controls == null) {
+ return;
+ }
+ for (InsetsSourceControl control : controls) {
+ final @InternalInsetsType int type = control.getType();
+ if (mShowingTransientTypes.indexOf(type) != -1) {
+ // The visibilities of transient bars will be handled with animations.
+ continue;
+ }
+ final SurfaceControl leash = control.getLeash();
+ if (leash != null) {
+ hasLeash = true;
+
+ // We use alpha to control the visibility here which aligns the logic at
+ // SurfaceAnimator.createAnimationLeash
+ mDisplayContent.getPendingTransaction().setAlpha(
+ leash, InsetsState.getDefaultVisibility(type) ? 1f : 0f);
+ }
+ }
+ if (hasLeash) {
+ mDisplayContent.scheduleAnimation();
+ }
+ }
+ };
private WindowState mFocusedWin;
private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 56986c2..a6a21fc 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -166,11 +166,18 @@
return;
}
- mTmpRect.set(mWin.getFrameLw());
- if (mFrameProvider != null) {
- mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
+ // Make sure we set the valid source frame only when server visible is true, because the
+ // frame may not yet determined that server side doesn't think the window is ready to
+ // visible. (i.e. No surface, pending insets that were given during layout, etc..)
+ if (mServerVisible) {
+ mTmpRect.set(mWin.getFrameLw());
+ if (mFrameProvider != null) {
+ mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
+ } else {
+ mTmpRect.inset(mWin.mGivenContentInsets);
+ }
} else {
- mTmpRect.inset(mWin.mGivenContentInsets);
+ mTmpRect.setEmpty();
}
mSource.setFrame(mTmpRect);
@@ -212,6 +219,8 @@
return;
}
+ setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
+ && !mWin.mGivenInsetsPending);
updateSourceFrame();
if (mControl != null) {
final Rect frame = mWin.getWindowFrames().mFrame;
@@ -221,8 +230,6 @@
mStateController.notifyControlChanged(mControlTarget);
}
}
- setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
- && !mWin.mGivenInsetsPending);
}
/**
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 4cd3180..513be7a 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -146,7 +146,10 @@
if (mTmpParams.hasWindowingMode()
&& mTmpParams.mWindowingMode != task.getStack().getWindowingMode()) {
- task.getStack().setWindowingMode(mTmpParams.mWindowingMode);
+ final int activityType = activity != null
+ ? activity.getActivityType() : task.getActivityType();
+ task.getStack().setWindowingMode(task.getDisplayArea().validateWindowingMode(
+ mTmpParams.mWindowingMode, activity, task, activityType));
}
if (mTmpParams.mBounds.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index c96c664..cbc1bdf 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -734,13 +734,10 @@
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
mTargetActivityRecord.token);
- } else {
- // The target activity will be moved to original position (non-top). Since it won't
- // affect display orientation, just finish the transform.
- mTargetActivityRecord.finishFixedRotationTransform();
}
}
- mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
+ mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(
+ reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION /* moveRecentsToBack */);
// Notify that the animation has ended
if (mStatusBar != null) {
@@ -802,7 +799,8 @@
// Only apply the input consumer if it is enabled, it is not the target (home/recents)
// being revealed with the transition, and we are actively animating the app as a part of
// the animation
- return mInputConsumerEnabled && !isTargetApp(activity) && isAnimatingApp(activity);
+ return mInputConsumerEnabled && activity != null
+ && !isTargetApp(activity) && isAnimatingApp(activity);
}
boolean updateInputConsumerForApp(InputWindowHandle inputWindowHandle,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 590e6f8..0ecde72 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -327,7 +327,7 @@
documentData = isDocument ? intent.getData() : null;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + parent);
- parent.forAllTasks(this);
+ parent.forAllLeafTasks(this);
}
void clear() {
@@ -2170,12 +2170,16 @@
final boolean singleActivity = task.getChildCount() == 1;
final ActivityStack stack;
if (singleActivity) {
- stack = r.getRootTask();
+ stack = (ActivityStack) task;
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task.
stack = taskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED, r.getActivityType(),
ON_TOP, r.info, r.intent, false /* createdByOrganizer */);
+ // It's possible the task entering PIP is in freeform, so save the last
+ // non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
+ // to its previous freeform bounds.
+ stack.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
@@ -2183,6 +2187,15 @@
// up-to-dated pinned stack information on this newly created stack.
r.reparent(stack, MAX_VALUE, reason);
}
+ if (stack.getParent() != taskDisplayArea) {
+ // stack is nested, but pinned tasks need to be direct children of their
+ // display area, so reparent.
+ stack.reparent(taskDisplayArea, true /* onTop */);
+ }
+ // Defer the windowing mode change until after the transition to prevent the activity
+ // from doing work and changing the activity visuals while animating
+ // TODO(task-org): Figure-out more structured way to do this long term.
+ r.setWindowingMode(stack.getWindowingMode());
stack.setWindowingMode(WINDOWING_MODE_PINNED);
// Reset the state that indicates it can enter PiP while pausing after we've moved it
@@ -2504,20 +2517,6 @@
return list;
}
- void deferUpdateBounds(int activityType) {
- final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- stack.deferUpdateBounds();
- }
- }
-
- void continueUpdateBounds(int activityType) {
- final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- stack.continueUpdateBounds();
- }
- }
-
@Override
public void onDisplayAdded(int displayId) {
if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 90936ef..14ab2e3 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -732,13 +732,6 @@
mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
kill();
mService.updateRotation(false, false);
- AccessibilityController accessibilityController = mService.mAccessibilityController;
-
- if (accessibilityController != null) {
- // We just finished rotation animation which means we did not
- // announce the rotation and waited for it to end, announce now.
- accessibilityController.onRotationChangedLocked(mDisplayContent);
- }
}
}
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index c79cb04..3d305e4 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -45,11 +45,22 @@
private final float[] mFloat9 = new float[9];
private final int mOldRotation;
private final int mNewRotation;
+ /* If the seamless rotator is used to rotate part of the hierarchy, then provide a transform
+ * hint based on the display orientation if the entire display was rotated. When the display
+ * orientation matches the hierarchy orientation, the fixed transform hint will be removed.
+ * This will prevent allocating different buffer sizes by the graphic producers when the
+ * orientation of a layer changes.
+ */
+ private final boolean mApplyFixedTransformHint;
+ private final int mFixedTransformHint;
- public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info) {
+
+ public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info,
+ boolean applyFixedTransformationHint) {
mOldRotation = oldRotation;
mNewRotation = newRotation;
-
+ mApplyFixedTransformHint = applyFixedTransformationHint;
+ mFixedTransformHint = oldRotation;
final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
final int pH = flipped ? info.logicalWidth : info.logicalHeight;
final int pW = flipped ? info.logicalHeight : info.logicalWidth;
@@ -70,6 +81,9 @@
final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
mTransform.mapPoints(winSurfacePos);
transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]);
+ if (mApplyFixedTransformHint) {
+ transaction.setFixedTransformHint(win.mSurfaceControl, mFixedTransformHint);
+ }
}
/**
@@ -109,6 +123,9 @@
mTransform.reset();
t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
+ if (mApplyFixedTransformHint) {
+ t.unsetFixedTransformHint(win.mSurfaceControl);
+ }
}
public void dump(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index bf20cb9..e225809 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -91,6 +91,7 @@
private float mLastReportedAnimatorScale;
private String mPackageName;
private String mRelayoutTag;
+ private final InsetsSourceControl[] mDummyControls = new InsetsSourceControl[0];
public Session(WindowManagerService service, IWindowSessionCallback callback) {
mService = service;
@@ -184,7 +185,7 @@
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
new Rect() /* outFrame */, outContentInsets, outStableInsets,
new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
- outInsetsState, null, UserHandle.getUserId(mUid));
+ outInsetsState, mDummyControls, UserHandle.getUserId(mUid));
}
@Override
@@ -661,17 +662,23 @@
@Override
public void grantInputChannel(int displayId, SurfaceControl surface,
- IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) {
+ IWindow window, IBinder hostInputToken, int flags, int type,
+ InputChannel outInputChannel) {
if (hostInputToken == null && !mCanAddInternalSystemWindow) {
// Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
// embedded windows without providing a host window input token
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
+ if (!mCanAddInternalSystemWindow && type != 0) {
+ Slog.w(TAG_WM, "Requires INTERNAL_SYSTEM_WINDOW permission if assign type to"
+ + " input");
+ }
+
final long identity = Binder.clearCallingIdentity();
try {
mService.grantInputChannel(mUid, mPid, displayId, surface, window, hostInputToken,
- flags, outInputChannel);
+ flags, mCanAddInternalSystemWindow ? type : 0, outInputChannel);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 18e32c0..0143eb1 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -109,7 +109,10 @@
animationFinishCallback.onAnimationFinished(type, anim);
}
};
- if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) {
+ // If both the Animatable and AnimationAdapter requests to be deferred, only the
+ // first one will be called.
+ if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)
+ || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) {
resetAndInvokeFinish.run();
}
}
@@ -486,6 +489,12 @@
static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
/**
+ * Animation when a fixed rotation transform is applied to a window token.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
+
+ /**
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
* @hide
*/
@@ -502,7 +511,8 @@
ANIMATION_TYPE_DIMMER,
ANIMATION_TYPE_RECENTS,
ANIMATION_TYPE_WINDOW_ANIMATION,
- ANIMATION_TYPE_INSETS_CONTROL
+ ANIMATION_TYPE_INSETS_CONTROL,
+ ANIMATION_TYPE_FIXED_TRANSFORM
})
@Retention(RetentionPolicy.SOURCE)
@interface AnimationType {}
@@ -592,6 +602,12 @@
* Gets called when the animation is about to finish and gives the client the opportunity to
* defer finishing the animation, i.e. it keeps the leash around until the client calls
* {@link #cancelAnimation}.
+ * <p>
+ * {@link AnimationAdapter} has a similar method which is called only if this method returns
+ * false. This mean that if both this {@link Animatable} and the {@link AnimationAdapter}
+ * request to be deferred, this method is the sole responsible to call
+ * endDeferFinishCallback. On the other hand, the animation finish might still be deferred
+ * if this method return false and the one from the {@link AnimationAdapter} returns true.
*
* @param endDeferFinishCallback The callback to call when defer finishing should be ended.
* @return Whether the client would like to defer the animation finish.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 44a8daa..cc72dcf 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -18,7 +18,6 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
@@ -29,7 +28,6 @@
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -82,7 +80,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.TAG_STACK;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
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;
@@ -110,7 +107,6 @@
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
-import android.app.PictureInPictureParams;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -491,12 +487,6 @@
boolean mTaskAppearedSent;
/**
- * Last Picture-in-Picture params applicable to the task. Updated when the app
- * enters Picture-in-Picture or when setPictureInPictureParams is called.
- */
- PictureInPictureParams mPictureInPictureParams = new PictureInPictureParams.Builder().build();
-
- /**
* This task was created by the task organizer which has the following implementations.
* <ul>
* <lis>The task won't be removed when it is empty. Removal has to be an explicit request
@@ -662,7 +652,7 @@
updateTaskDescription();
}
- boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
+ boolean resize(Rect bounds, int resizeMode, boolean preserveWindow) {
mAtmService.deferWindowLayout();
try {
@@ -702,7 +692,7 @@
boolean kept = true;
if (updatedConfig) {
final ActivityRecord r = topRunningActivityLocked();
- if (r != null && !deferResume) {
+ if (r != null) {
kept = r.ensureActivityConfiguration(0 /* globalChanges */,
preserveWindow);
// Preserve other windows for resizing because if resizing happens when there
@@ -854,30 +844,11 @@
// TODO: Should this call be moved inside the resize method in WM?
toStack.prepareFreezingTaskBounds();
- // Make sure the task has the appropriate bounds/size for the stack it is in.
- final boolean toStackSplitScreenPrimary =
- toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
- final Rect configBounds = getRequestedOverrideBounds();
- if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
- || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
- && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
- kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
- !mightReplaceWindow, deferResume);
- } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
- Rect bounds = getLaunchBounds();
- if (bounds == null) {
- mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
- bounds = configBounds;
- }
- kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
- } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
- if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
- // Move recents to front so it is not behind home stack when going into docked
- // mode
- mStackSupervisor.moveRecentsStackToFront(reason);
- }
- kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
- !mightReplaceWindow, deferResume);
+ if (toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
+ // Move recents to front so it is not behind home stack when going into docked
+ // mode
+ mStackSupervisor.moveRecentsStackToFront(reason);
}
} finally {
mAtmService.continueWindowLayout();
@@ -971,7 +942,7 @@
return;
}
- affinity = info.taskAffinity;
+ affinity = isLeafTask() ? info.taskAffinity : null;
if (intent == null) {
// If this task already has an intent associated with it, don't set the root
// affinity -- we don't want it changing after initially set, but the initially
@@ -1969,7 +1940,6 @@
setLastNonFullscreenBounds(currentBounds);
}
}
- // TODO: Should also take care of Pip mode changes here.
saveLaunchingStateIfNeeded();
final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */);
@@ -2013,7 +1983,7 @@
}
void updateSurfaceSize(SurfaceControl.Transaction transaction) {
- if (mSurfaceControl == null || mCreatedByOrganizer) {
+ if (mSurfaceControl == null || isOrganized()) {
return;
}
@@ -3059,15 +3029,6 @@
return mDragResizeMode;
}
- /**
- * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
- *
- * @param resizing Whether to put the task into drag resize mode.
- */
- public void setTaskDockedResizing(boolean resizing) {
- setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
- }
-
void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
if (displayContent == null) {
return;
@@ -3438,6 +3399,24 @@
}
@Override
+ boolean forAllLeafTasks(Function<Task, Boolean> callback) {
+ boolean isLeafTask = true;
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final Task child = mChildren.get(i).asTask();
+ if (child != null) {
+ isLeafTask = false;
+ if (child.forAllLeafTasks(callback)) {
+ return true;
+ }
+ }
+ }
+ if (isLeafTask) {
+ return callback.apply(this);
+ }
+ return false;
+ }
+
+ @Override
Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
final Task t = super.getTask(callback, traverseTopToBottom);
if (t != null) return t;
@@ -3602,10 +3581,11 @@
info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
info.topActivityType = top.getActivityType();
- if (mPictureInPictureParams.empty()) {
+ ActivityRecord rootActivity = top.getRootActivity();
+ if (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) {
info.pictureInPictureParams = null;
} else {
- info.pictureInPictureParams = mPictureInPictureParams;
+ info.pictureInPictureParams = rootActivity.pictureInPictureArgs;
}
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
@@ -4521,8 +4501,7 @@
updateShadowsRadius(hasFocus, getPendingTransaction());
}
- void setPictureInPictureParams(PictureInPictureParams p) {
- mPictureInPictureParams.copyOnlySet(p);
+ void onPictureInPictureParamsChanged() {
if (isOrganized()) {
mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */);
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 7d0c6aa..6ce36f1 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -1333,16 +1332,16 @@
}
/**
- * Check that the requested windowing-mode is appropriate for the specified task and/or activity
+ * Check if the requested windowing-mode is appropriate for the specified task and/or activity
* on this display.
*
* @param windowingMode The windowing-mode to validate.
* @param r The {@link ActivityRecord} to check against.
* @param task The {@link Task} to check against.
* @param activityType An activity type.
- * @return The provided windowingMode or the closest valid mode which is appropriate.
+ * @return {@code true} if windowingMode is valid, {@code false} otherwise.
*/
- int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+ boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
int activityType) {
// Make sure the windowing mode we are trying to use makes sense for what is supported.
boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
@@ -1362,24 +1361,35 @@
}
}
+ return windowingMode != WINDOWING_MODE_UNDEFINED
+ && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+ supportsFreeform, supportsPip, activityType);
+ }
+
+ /**
+ * Check that the requested windowing-mode is appropriate for the specified task and/or activity
+ * on this display.
+ *
+ * @param windowingMode The windowing-mode to validate.
+ * @param r The {@link ActivityRecord} to check against.
+ * @param task The {@link Task} to check against.
+ * @param activityType An activity type.
+ * @return The provided windowingMode or the closest valid mode which is appropriate.
+ */
+ int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+ int activityType) {
final boolean inSplitScreenMode = isSplitScreenModeActivated();
- if (!inSplitScreenMode
- && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+ if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
// Switch to the display's windowing mode if we are not in split-screen mode and we are
// trying to launch in split-screen secondary.
windowingMode = WINDOWING_MODE_UNDEFINED;
- } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_UNDEFINED)
- && supportsSplitScreen) {
+ } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
}
-
- if (windowingMode != WINDOWING_MODE_UNDEFINED
- && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
- supportsFreeform, supportsPip, activityType)) {
- return windowingMode;
+ if (!isValidWindowingMode(windowingMode, r, task, activityType)) {
+ return WINDOWING_MODE_UNDEFINED;
}
- return WINDOWING_MODE_UNDEFINED;
+ return windowingMode;
}
boolean isTopStack(ActivityStack stack) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 0f5cafe..1a2672b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -297,6 +297,13 @@
Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
return false;
}
+ if (activity.hasFixedRotationTransform()) {
+ if (DEBUG_SCREENSHOT) {
+ Slog.i(TAG_WM, "Skip taking screenshot. App has fixed rotation " + activity);
+ }
+ // The activity is in a temporal state that it has different rotation than the task.
+ return false;
+ }
builder.setIsRealSnapshot(true);
builder.setId(System.currentTimeMillis());
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 45023ac..c6e1c95 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -28,12 +28,14 @@
import android.graphics.Bitmap.Config;
import android.os.Process;
import android.os.SystemClock;
+import android.os.UserManagerInternal;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
import java.io.File;
@@ -72,6 +74,7 @@
private final float mLowResScaleFactor;
private boolean mEnableLowResSnapshots;
private final boolean mUse16BitFormat;
+ private final UserManagerInternal mUserManagerInternal;
/**
* The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
@@ -82,6 +85,8 @@
TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
mDirectoryResolver = resolver;
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+
final float highResTaskSnapshotScale = service.mContext.getResources().getFloat(
com.android.internal.R.dimen.config_highResTaskSnapshotScale);
final float lowResTaskSnapshotScale = service.mContext.getResources().getFloat(
@@ -191,7 +196,7 @@
return;
}
}
- SystemClock.sleep(100);
+ SystemClock.sleep(DELAY_MS);
}
}
@@ -233,7 +238,7 @@
private boolean createDirectory(int userId) {
final File dir = getDirectory(userId);
- return dir.exists() || dir.mkdirs();
+ return dir.exists() || dir.mkdir();
}
private void deleteSnapshot(int taskId, int userId) {
@@ -258,18 +263,26 @@
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
WriteQueueItem next;
+ boolean isReadyToWrite = false;
synchronized (mLock) {
if (mPaused) {
next = null;
} else {
next = mWriteQueue.poll();
if (next != null) {
- next.onDequeuedLocked();
+ if (next.isReady()) {
+ isReadyToWrite = true;
+ next.onDequeuedLocked();
+ } else {
+ mWriteQueue.addLast(next);
+ }
}
}
}
if (next != null) {
- next.write();
+ if (isReadyToWrite) {
+ next.write();
+ }
SystemClock.sleep(DELAY_MS);
}
synchronized (mLock) {
@@ -289,6 +302,13 @@
};
private abstract class WriteQueueItem {
+ /**
+ * @return {@code true} if item is ready to have {@link WriteQueueItem#write} called
+ */
+ boolean isReady() {
+ return true;
+ }
+
abstract void write();
/**
@@ -328,6 +348,11 @@
}
@Override
+ boolean isReady() {
+ return mUserManagerInternal.isUserUnlocked(mUserId);
+ }
+
+ @Override
void write() {
if (!createDirectory(mUserId)) {
Slog.e(TAG, "Unable to create snapshot directory for user dir="
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 24cd7d1..3925570 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -195,6 +195,16 @@
+ activity);
return null;
}
+ if (topFullscreenActivity.getWindowConfiguration().getRotation()
+ != snapshot.getRotation()) {
+ // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
+ // that the activity will be updated to the same rotation as the snapshot. Since
+ // the transition is not started yet, fixed rotation transform needs to be applied
+ // earlier to make the snapshot show in a rotated container.
+ activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
+ topFullscreenActivity, false /* checkOpening */);
+ }
+
sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
windowFlags = attrs.flags;
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 79baab6..06c2b16 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -48,6 +48,16 @@
mDisplayContent = displayContent;
}
+ private void restorePointerIcon(int x, int y) {
+ if (mPointerIconType != TYPE_NOT_SPECIFIED) {
+ mPointerIconType = TYPE_NOT_SPECIFIED;
+ // Find the underlying window and ask it to restore the pointer icon.
+ mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
+ mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
+ x, y, mDisplayContent).sendToTarget();
+ }
+ }
+
@Override
public void onPointerEvent(MotionEvent motionEvent) {
switch (motionEvent.getActionMasked()) {
@@ -67,6 +77,10 @@
case MotionEvent.ACTION_HOVER_MOVE: {
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
+ if (mTouchExcludeRegion.contains(x, y)) {
+ restorePointerIcon(x, y);
+ break;
+ }
final Task task = mDisplayContent.findTaskForResizePoint(x, y);
int iconType = TYPE_NOT_SPECIFIED;
if (task != null) {
@@ -103,13 +117,7 @@
case MotionEvent.ACTION_HOVER_EXIT: {
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
- if (mPointerIconType != TYPE_NOT_SPECIFIED) {
- mPointerIconType = TYPE_NOT_SPECIFIED;
- // Find the underlying window and ask it to restore the pointer icon.
- mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
- mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
- x, y, mDisplayContent).sendToTarget();
- }
+ restorePointerIcon(x, y);
}
break;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index b9b6c08..d1cb210 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -238,23 +238,12 @@
}
}
- private final boolean isWallpaperVisible(WindowState wallpaperTarget) {
- final RecentsAnimationController recentsAnimationController =
- mService.getRecentsAnimationController();
- boolean isAnimatingWithRecentsComponent = recentsAnimationController != null
- && recentsAnimationController.isWallpaperVisible(wallpaperTarget);
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
- + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
- + " animating=" + ((wallpaperTarget != null && wallpaperTarget.mActivityRecord != null)
- ? wallpaperTarget.mActivityRecord.isAnimating(TRANSITION | PARENTS) : null)
- + " prev=" + mPrevWallpaperTarget
- + " recentsAnimationWallpaperVisible=" + isAnimatingWithRecentsComponent);
- return (wallpaperTarget != null
- && (!wallpaperTarget.mObscured
- || isAnimatingWithRecentsComponent
- || (wallpaperTarget.mActivityRecord != null
- && wallpaperTarget.mActivityRecord.isAnimating(TRANSITION | PARENTS))))
- || mPrevWallpaperTarget != null;
+ private boolean isWallpaperVisible(WindowState wallpaperTarget) {
+ if (DEBUG_WALLPAPER) {
+ Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + " prev="
+ + mPrevWallpaperTarget);
+ }
+ return wallpaperTarget != null || mPrevWallpaperTarget != null;
}
boolean isWallpaperTargetAnimating() {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 5f3c633..132d00a 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -123,19 +123,20 @@
}
final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+ final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
- if (visible) {
- final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
+ if (visible && wallpaperTarget != null) {
final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController();
- if (wallpaperTarget != null
- && recentsAnimationController != null
+ if (recentsAnimationController != null
&& recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) {
// If the Recents animation is running, and the wallpaper target is the animating
// task we want the wallpaper to be rotated in the same orientation as the
// RecentsAnimation's target (e.g the launcher)
recentsAnimationController.linkFixedRotationTransformIfNeeded(this);
- } else if (wallpaperTarget != null
+ } else if ((wallpaperTarget.mActivityRecord == null
+ // Ignore invisible activity because it may be moving to background.
+ || wallpaperTarget.mActivityRecord.mVisibleRequested)
&& wallpaperTarget.mToken.hasFixedRotationTransform()) {
// If the wallpaper target has a fixed rotation, we want the wallpaper to follow its
// rotation
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 3f8d7b5..7bfddd7 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1552,6 +1552,15 @@
return false;
}
+ boolean forAllLeafTasks(Function<Task, Boolean> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ if (mChildren.get(i).forAllLeafTasks(callback)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* For all tasks at or below this container call the callback.
*
@@ -2111,6 +2120,11 @@
return getBounds();
}
+ /** Gets the position relative to parent for animation. */
+ void getAnimationPosition(Point outPosition) {
+ getRelativePosition(outPosition);
+ }
+
/**
* Applies the app transition animation according the given the layout properties in the
* window hierarchy.
@@ -2169,9 +2183,9 @@
// Separate position and size for use in animators.
mTmpRect.set(getAnimationBounds(appStackClipMode));
- if (sHierarchicalAnimations) {
- getRelativePosition(mTmpPoint);
- } else {
+ getAnimationPosition(mTmpPoint);
+ if (!sHierarchicalAnimations) {
+ // Non-hierarchical animation uses position in global coordinates.
mTmpPoint.set(mTmpRect.left, mTmpRect.top);
}
mTmpRect.offsetTo(0, 0);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 07840b5..5c21b2b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -72,6 +72,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManagerGlobal.ADD_OKAY;
@@ -195,6 +196,7 @@
import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
+import android.sysprop.SurfaceFlingerProperties;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -304,7 +306,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -926,8 +930,14 @@
}
void updateFixedRotationTransform() {
- mIsFixedRotationTransformEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
+ final int enabled = Settings.Global.getInt(mContext.getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 2);
+ if (enabled == 2) {
+ // Make sure who read the settings won't use inconsistent default value.
+ Settings.Global.putInt(mContext.getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 1);
+ }
+ mIsFixedRotationTransformEnabled = enabled != 0;
}
}
@@ -1057,12 +1067,10 @@
@Override
public void onAppTransitionCancelledLocked(int transit) {
- mAtmInternal.notifyAppTransitionCancelled();
}
@Override
public void onAppTransitionFinishedLocked(IBinder token) {
- mAtmInternal.notifyAppTransitionFinished();
final ActivityRecord atoken = mRoot.getActivityRecord(token);
if (atoken == null) {
return;
@@ -1367,6 +1375,7 @@
case TYPE_NOTIFICATION_SHADE:
case TYPE_NAVIGATION_BAR:
case TYPE_INPUT_METHOD_DIALOG:
+ case TYPE_VOLUME_OVERLAY:
return true;
}
return false;
@@ -1378,6 +1387,7 @@
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
int requestUserId) {
+ Arrays.fill(outActiveControls, null);
int[] appOp = new int[1];
final boolean isRoundedCornerOverlay = (attrs.privateFlags
& PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
@@ -2124,6 +2134,7 @@
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
SurfaceControl outBLASTSurfaceControl) {
+ Arrays.fill(outActiveControls, null);
int result = 0;
boolean configChanged;
final int pid = Binder.getCallingPid();
@@ -2250,7 +2261,7 @@
win.mRelayoutCalled = true;
win.mInRelayout = true;
- win.mViewVisibility = viewVisibility;
+ win.setViewVisibility(viewVisibility);
ProtoLog.i(WM_DEBUG_SCREEN_ON,
"Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,
viewVisibility, new RuntimeException().fillInStackTrace());
@@ -2461,23 +2472,20 @@
}
private void getInsetsSourceControls(WindowState win, InsetsSourceControl[] outControls) {
- if (outControls != null) {
- final InsetsSourceControl[] controls =
- win.getDisplayContent().getInsetsStateController().getControlsForDispatch(win);
- Arrays.fill(outControls, null);
- if (controls != null) {
- final int length = Math.min(controls.length, outControls.length);
- for (int i = 0; i < length; i++) {
- // We will leave the critical section before returning the leash to the client,
- // so we need to copy the leash to prevent others release the one that we are
- // about to return.
- // TODO: We will have an extra copy if the client is not local.
- // For now, we rely on GC to release it.
- // Maybe we can modify InsetsSourceControl.writeToParcel so it can release
- // the extra leash as soon as possible.
- outControls[i] = controls[i] != null
- ? new InsetsSourceControl(controls[i]) : null;
- }
+ final InsetsSourceControl[] controls =
+ win.getDisplayContent().getInsetsStateController().getControlsForDispatch(win);
+ if (controls != null) {
+ final int length = Math.min(controls.length, outControls.length);
+ for (int i = 0; i < length; i++) {
+ // We will leave the critical section before returning the leash to the client,
+ // so we need to copy the leash to prevent others release the one that we are
+ // about to return.
+ // TODO: We will have an extra copy if the client is not local.
+ // For now, we rely on GC to release it.
+ // Maybe we can modify InsetsSourceControl.writeToParcel so it can release
+ // the extra leash as soon as possible.
+ outControls[i] = controls[i] != null
+ ? new InsetsSourceControl(controls[i]) : null;
}
}
}
@@ -4686,6 +4694,11 @@
}
private static boolean queryWideColorGamutSupport() {
+ boolean defaultValue = false;
+ Optional<Boolean> hasWideColorProp = SurfaceFlingerProperties.has_wide_color_display();
+ if (hasWideColorProp.isPresent()) {
+ return hasWideColorProp.get();
+ }
try {
ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
OptionalBool hasWideColor = surfaceFlinger.hasWideColorDisplay();
@@ -4694,11 +4707,18 @@
}
} catch (RemoteException e) {
// Ignore, we're in big trouble if we can't talk to SurfaceFlinger's config store
+ } catch (NoSuchElementException e) {
+ return defaultValue;
}
return false;
}
private static boolean queryHdrSupport() {
+ boolean defaultValue = false;
+ Optional<Boolean> hasHdrProp = SurfaceFlingerProperties.has_HDR_display();
+ if (hasHdrProp.isPresent()) {
+ return hasHdrProp.get();
+ }
try {
ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
OptionalBool hasHdr = surfaceFlinger.hasHDRDisplay();
@@ -4707,6 +4727,8 @@
}
} catch (RemoteException e) {
// Ignore, we're in big trouble if we can't talk to SurfaceFlinger's config store
+ } catch (NoSuchElementException e) {
+ return defaultValue;
}
return false;
}
@@ -8004,45 +8026,31 @@
* views.
*/
void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceControl surface,
- IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) {
+ IWindow window, IBinder hostInputToken, int flags, int type,
+ InputChannel outInputChannel) {
final InputApplicationHandle applicationHandle;
final String name;
- final InputChannel[] inputChannels;
final InputChannel clientChannel;
- final InputChannel serverChannel;
synchronized (mGlobalLock) {
EmbeddedWindowController.EmbeddedWindow win =
- new EmbeddedWindowController.EmbeddedWindow(window,
- mInputToWindowMap.get(hostInputToken), callingUid, callingPid);
- name = win.getName();
-
- inputChannels = InputChannel.openInputChannelPair(name);
- serverChannel = inputChannels[0];
- clientChannel = inputChannels[1];
- mInputManager.registerInputChannel(serverChannel);
+ new EmbeddedWindowController.EmbeddedWindow(this, window,
+ mInputToWindowMap.get(hostInputToken), callingUid, callingPid, type);
+ clientChannel = win.openInputChannel();
mEmbeddedWindowController.add(clientChannel.getToken(), win);
- if (serverChannel.getToken() != clientChannel.getToken()) {
- throw new IllegalStateException("Client and Server channel are expected to"
- + "be the same");
- }
-
applicationHandle = win.getApplicationHandle();
+ name = win.getName();
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
- name, applicationHandle, flags, null /* region */);
+ name, applicationHandle, flags, type, null /* region */);
clientChannel.transferTo(outInputChannel);
clientChannel.dispose();
- // Prevent the java finalizer from breaking the input channel. But we won't
- // do any further management so we just release the java ref and let the
- // InputDispatcher hold the last ref.
- serverChannel.release();
}
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
int displayId, SurfaceControl surface, String name,
- InputApplicationHandle applicationHandle, int flags, Region region) {
+ InputApplicationHandle applicationHandle, int flags, int type, Region region) {
InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.token = channelToken;
h.name = name;
@@ -8050,7 +8058,7 @@
final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE
| LayoutParams.FLAG_SLIPPERY);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
- h.layoutParamsType = 0;
+ h.layoutParamsType = type;
h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
h.canReceiveKeys = false;
h.hasFocus = false;
@@ -8074,6 +8082,7 @@
t.setInputWindowInfo(surface, h);
t.apply();
t.close();
+ surface.release();
}
/**
@@ -8097,7 +8106,7 @@
}
updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
- applicationHandle, flags, region);
+ applicationHandle, flags, win.mWindowType, region);
}
/** Return whether layer tracing is enabled */
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index c4cb4b5..707a789 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -138,6 +138,13 @@
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
continue;
}
+ // Make sure we add to the syncSet before performing
+ // operations so we don't end up splitting effects between the WM
+ // pending transaction and the BLASTSync transaction.
+ if (syncId >= 0) {
+ mBLASTSyncEngine.addToSyncSet(syncId, wc);
+ }
+
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
effects |= containerEffect;
@@ -146,9 +153,6 @@
&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
haveConfigChanges.add(wc);
}
- if (syncId >= 0) {
- mBLASTSyncEngine.addToSyncSet(syncId, wc);
- }
}
// Hierarchy changes
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f6473fd..e925ce5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -741,7 +741,8 @@
if (mControllableInsetProvider != null) {
mControllableInsetProvider.startSeamlessRotation();
}
- mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo());
+ mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo(),
+ false /* applyFixedTransformationHint */);
mPendingSeamlessRotate.unrotate(transaction, this);
getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
true /* seamlesslyRotated */);
@@ -5688,6 +5689,17 @@
return mSession.mPid == pid && isNonToastOrStarting() && isVisibleNow();
}
+ void setViewVisibility(int viewVisibility) {
+ mViewVisibility = viewVisibility;
+ // The viewVisibility is set to GONE with a client request to relayout. If this occurs and
+ // there's a blast sync transaction waiting, finishDrawing will never be called since the
+ // client will not render when visibility is GONE. Therefore, call finishDrawing here to
+ // prevent system server from blocking on a window that will not draw.
+ if (viewVisibility == View.GONE && mUsingBLASTSyncTransaction) {
+ finishDrawing(null);
+ }
+ }
+
SurfaceControl getClientViewRootSurface() {
return mWinAnimator.getClientViewRootSurface();
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0e83bee..c570cf1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -846,6 +846,23 @@
}
}
+ private boolean shouldConsumeMainWindowSizeTransaction() {
+ // We only consume the transaction when the client is calling relayout
+ // because this is the only time we know the frameNumber will be valid
+ // due to the client renderer being paused. Put otherwise, only when
+ // mInRelayout is true can we guarantee the next frame will contain
+ // the most recent configuration.
+ if (!mWin.mInRelayout) return false;
+ // Since we can only do this for one window, we focus on the main application window
+ if (mAttrType != TYPE_BASE_APPLICATION) return false;
+ final Task task = mWin.getTask();
+ if (task == null) return false;
+ if (task.getMainWindowSizeChangeTransaction() == null) return false;
+ // Likewise we only focus on the task root, since we can only use one window
+ if (!mWin.mActivityRecord.isRootOfTask()) return false;
+ return true;
+ }
+
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
if (mSurfaceController == null) {
return;
@@ -886,8 +903,9 @@
clipRect = mTmpClipRect;
}
- if (w.mInRelayout && (mAttrType == TYPE_BASE_APPLICATION) && (task != null)
- && (task.getMainWindowSizeChangeTransaction() != null)) {
+ if (shouldConsumeMainWindowSizeTransaction()) {
+ task.getSurfaceControl().deferTransactionUntil(mWin.getClientViewRootSurface(),
+ mWin.getFrameNumber());
mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
mWin.getFrameNumber());
SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 472773e..8739bad 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -19,6 +19,7 @@
import static android.os.Process.INVALID_UID;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -40,6 +41,7 @@
import android.annotation.CallSuper;
import android.app.IWindowToken;
+import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
@@ -47,6 +49,7 @@
import android.os.RemoteException;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.SurfaceControl;
@@ -141,7 +144,7 @@
mRotatedOverrideConfiguration = rotatedConfig;
// This will use unrotate as rotate, so the new and old rotation are inverted.
mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation,
- rotatedDisplayInfo);
+ rotatedDisplayInfo, true /* applyFixedTransformationHint */);
}
/**
@@ -529,6 +532,7 @@
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
insetsState, new Configuration(config), mDisplayContent.getRotation());
onConfigurationChanged(getParent().getConfiguration());
+ notifyFixedRotationTransform(true /* enabled */);
}
/**
@@ -546,6 +550,7 @@
mFixedRotationTransformState = fixedRotationState;
fixedRotationState.mAssociatedTokens.add(this);
onConfigurationChanged(getParent().getConfiguration());
+ notifyFixedRotationTransform(true /* enabled */);
}
void finishFixedRotationTransform() {
@@ -578,9 +583,52 @@
// The state is cleared at the end, because it is used to indicate that other windows can
// use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
- state.mAssociatedTokens.get(i).mFixedRotationTransformState = null;
+ state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState();
}
+ cleanUpFixedRotationTransformState();
+ }
+
+ private void cleanUpFixedRotationTransformState() {
mFixedRotationTransformState = null;
+ notifyFixedRotationTransform(false /* enabled */);
+ }
+
+ /** Notifies application side to enable or disable the rotation adjustment of display info. */
+ private void notifyFixedRotationTransform(boolean enabled) {
+ FixedRotationAdjustments adjustments = null;
+ // A token may contain windows of the same processes or different processes. The list is
+ // used to avoid sending the same adjustments to a process multiple times.
+ ArrayList<WindowProcessController> notifiedProcesses = null;
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowState w = mChildren.get(i);
+ final WindowProcessController app;
+ if (w.mAttrs.type == TYPE_APPLICATION_STARTING) {
+ // Use the host activity because starting window is controlled by window manager.
+ final ActivityRecord r = asActivityRecord();
+ if (r == null) {
+ continue;
+ }
+ app = r.app;
+ } else {
+ app = mWmService.mAtmService.mProcessMap.getProcess(w.mSession.mPid);
+ }
+ if (app == null || !app.hasThread()) {
+ continue;
+ }
+ if (notifiedProcesses == null) {
+ notifiedProcesses = new ArrayList<>(2);
+ adjustments = enabled ? createFixedRotationAdjustmentsIfNeeded() : null;
+ } else if (notifiedProcesses.contains(app)) {
+ continue;
+ }
+ notifiedProcesses.add(app);
+ try {
+ mWmService.mAtmService.getLifecycleManager().scheduleTransaction(
+ app.getThread(), FixedRotationAdjustmentsItem.obtain(token, adjustments));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to schedule DisplayAdjustmentsItem to " + app, e);
+ }
+ }
}
/** Restores the changes that applies to this container. */
@@ -590,9 +638,13 @@
// The window may be detached or detaching.
return;
}
+ notifyFixedRotationTransform(false /* enabled */);
final int originalRotation = getWindowConfiguration().getRotation();
onConfigurationChanged(parent.getConfiguration());
onCancelFixedRotationTransform(originalRotation);
+ if (mDisplayContent.mFixedRotationAnimationController != null) {
+ mDisplayContent.mFixedRotationAnimationController.cancel();
+ }
}
/**
@@ -603,6 +655,14 @@
void onCancelFixedRotationTransform(int originalDisplayRotation) {
}
+ FixedRotationAdjustments createFixedRotationAdjustmentsIfNeeded() {
+ if (!isFixedRotationTransforming()) {
+ return null;
+ }
+ return new FixedRotationAdjustments(mFixedRotationTransformState.mDisplayInfo.rotation,
+ mFixedRotationTransformState.mDisplayInfo.displayCutout);
+ }
+
@Override
void resolveOverrideConfiguration(Configuration newParentConfig) {
super.resolveOverrideConfiguration(newParentConfig);
@@ -671,6 +731,11 @@
pw.print(" waitingToShow=true");
}
pw.println();
+ if (hasFixedRotationTransform()) {
+ pw.print(prefix);
+ pw.print("fixedRotationConfig=");
+ pw.println(mFixedRotationTransformState.mRotatedOverrideConfiguration);
+ }
}
@Override
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
new file mode 100644
index 0000000..8646a53
--- /dev/null
+++ b/services/core/jni/OWNERS
@@ -0,0 +1,13 @@
+# Display
+per-file com_android_server_lights_LightsService.cpp = michaelwr@google.com, santoscordon@google.com
+
+# Haptics
+per-file com_android_server_VibratorService.cpp = michaelwr@google.com
+
+# Input
+per-file com_android_server_input_InputManagerService.cpp = michaelwr@google.com, svv@google.com
+
+# Power
+per-file com_android_server_HardwarePropertiesManagerService.cpp = michaelwr@google.com, santoscordon@google.com
+per-file com_android_server_power_PowerManagerService.* = michaelwr@google.com, santoscordon@google.com
+
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9bc5d34..2013945 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -237,27 +237,28 @@
/* --- InputDispatcherPolicyInterface implementation --- */
virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
- uint32_t policyFlags);
+ uint32_t policyFlags) override;
virtual void notifyConfigurationChanged(nsecs_t when);
- virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token,
- const std::string& reason);
+ virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) override;
virtual void notifyInputChannelBroken(const sp<IBinder>& token);
- virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken);
- virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
- virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
- virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken,
+ const sp<IBinder>& newToken) override;
+ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
+ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
+ uint32_t& policyFlags) override;
virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
- uint32_t& policyFlags);
- virtual nsecs_t interceptKeyBeforeDispatching(
- const sp<IBinder>& token,
- const KeyEvent* keyEvent, uint32_t policyFlags);
- virtual bool dispatchUnhandledKey(const sp<IBinder>& token,
- const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent);
- virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
- virtual bool checkInjectEventsPermissionNonReentrant(
- int32_t injectorPid, int32_t injectorUid);
- virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken);
+ uint32_t& policyFlags) override;
+ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
+ const KeyEvent* keyEvent,
+ uint32_t policyFlags) override;
+ virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
+ uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) override;
+ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) override;
+ virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
+ int32_t injectorUid) override;
+ virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
/* --- PointerControllerPolicyInterface implementation --- */
@@ -692,9 +693,8 @@
return handle->getInputApplicationHandleObjLocalRef(env);
}
-
-nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token, const std::string& reason) {
+nsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -1453,9 +1453,13 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
- & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
- uint32_t(policyFlags));
+ const int32_t result =
+ im->getInputManager()->getDispatcher()->injectInputEvent(&keyEvent, injectorPid,
+ injectorUid, syncMode,
+ std::chrono::milliseconds(
+ timeoutMillis),
+ uint32_t(policyFlags));
+ return static_cast<jint>(result);
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
if (!motionEvent) {
@@ -1463,9 +1467,13 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
- motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
- uint32_t(policyFlags));
+ const int32_t result =
+ (jint)im->getInputManager()
+ ->getDispatcher()
+ ->injectInputEvent(motionEvent, injectorPid, injectorUid, syncMode,
+ std::chrono::milliseconds(timeoutMillis),
+ uint32_t(policyFlags));
+ return static_cast<jint>(result);
} else {
jniThrowRuntimeException(env, "Invalid input event type.");
return INPUT_EVENT_INJECTION_FAILED;
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 6cf8133..e904645 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "PackageManagerShellCommandDataLoader-jni"
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/no_destructor.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <core_jni_helpers.h>
@@ -65,6 +66,7 @@
static constexpr MagicType INCR = 0x52434e49; // BE INCR
static constexpr auto PollTimeoutMs = 5000;
+static constexpr auto TraceTagCheckInterval = 1s;
struct JniIds {
jclass packageManagerShellCommandDataLoader;
@@ -337,9 +339,47 @@
return env;
}
-class PackageManagerShellCommandDataLoaderDataLoader : public android::dataloader::DataLoader {
+class PMSCDataLoader;
+
+struct OnTraceChanged {
+ OnTraceChanged();
+ ~OnTraceChanged() {
+ mRunning = false;
+ mChecker.join();
+ }
+
+ void registerCallback(PMSCDataLoader* callback) {
+ std::unique_lock lock(mMutex);
+ mCallbacks.insert(callback);
+ }
+
+ void unregisterCallback(PMSCDataLoader* callback) {
+ std::unique_lock lock(mMutex);
+ mCallbacks.erase(callback);
+ }
+
+private:
+ std::mutex mMutex;
+ std::unordered_set<PMSCDataLoader*> mCallbacks;
+ std::atomic<bool> mRunning{true};
+ std::thread mChecker;
+};
+
+static OnTraceChanged& onTraceChanged() {
+ static android::base::NoDestructor<OnTraceChanged> instance;
+ return *instance;
+}
+
+class PMSCDataLoader : public android::dataloader::DataLoader {
public:
- PackageManagerShellCommandDataLoaderDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
+ PMSCDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
+ ~PMSCDataLoader() { onTraceChanged().unregisterCallback(this); }
+
+ void updateReadLogsState(const bool enabled) {
+ if (enabled != mReadLogsEnabled.exchange(enabled)) {
+ mIfs->setParams({.readLogsEnabled = enabled});
+ }
+ }
private:
// Lifecycle.
@@ -353,7 +393,8 @@
mArgs = params.arguments();
mIfs = ifs;
mStatusListener = statusListener;
- mIfs->setParams({.readLogsEnabled = true});
+ updateReadLogsState(atrace_is_tag_enabled(ATRACE_TAG));
+ onTraceChanged().registerCallback(this);
return true;
}
bool onStart() final { return true; }
@@ -365,6 +406,7 @@
}
}
void onDestroy() final {
+ onTraceChanged().unregisterCallback(this);
// Make sure the receiver thread stopped.
CHECK(!mReceiverThread.joinable());
}
@@ -757,10 +799,28 @@
android::base::unique_fd mEventFd;
std::thread mReceiverThread;
std::atomic<bool> mStopReceiving = false;
+ std::atomic<bool> mReadLogsEnabled = false;
/** Tracks which files have been requested */
std::unordered_set<FileIdx> mRequestedFiles;
};
+OnTraceChanged::OnTraceChanged() {
+ mChecker = std::thread([this]() {
+ bool oldTrace = atrace_is_tag_enabled(ATRACE_TAG);
+ while (mRunning) {
+ bool newTrace = atrace_is_tag_enabled(ATRACE_TAG);
+ if (oldTrace != newTrace) {
+ std::unique_lock lock(mMutex);
+ for (auto&& callback : mCallbacks) {
+ callback->updateReadLogsState(newTrace);
+ }
+ }
+ oldTrace = newTrace;
+ std::this_thread::sleep_for(TraceTagCheckInterval);
+ }
+ });
+}
+
BlockHeader readHeader(std::span<uint8_t>& data) {
BlockHeader header;
if (data.size() < sizeof(header)) {
@@ -794,7 +854,7 @@
[](auto jvm, const auto& params) -> android::dataloader::DataLoaderPtr {
if (params.type() == DATA_LOADER_TYPE_INCREMENTAL) {
// This DataLoader only supports incremental installations.
- return std::make_unique<PackageManagerShellCommandDataLoaderDataLoader>(jvm);
+ return std::make_unique<PMSCDataLoader>(jvm);
}
return {};
});
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3323fa4..18c25c1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -247,6 +247,7 @@
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -984,6 +985,10 @@
// (ACTION_DATE_CHANGED), or when manual clock adjustment is made
// (ACTION_TIME_CHANGED)
updateSystemUpdateFreezePeriodsRecord(/* saveIfChanged */ true);
+ final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
+ if (userId >= 0) {
+ updatePersonalAppsSuspension(userId, mUserManager.isUserUnlocked(userId));
+ }
} else if (ACTION_PROFILE_OFF_DEADLINE.equals(action)) {
Slog.i(LOG_TAG, "Profile off deadline alarm was triggered");
final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
@@ -4567,9 +4572,11 @@
}
if (isProfileOwner(adminReceiver, userHandle)) {
if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) {
+ UserHandle parentUserHandle = UserHandle.of(getProfileParentId(userHandle));
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
- false,
- UserHandle.of(getProfileParentId(userHandle)));
+ false, parentUserHandle);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+ false, parentUserHandle);
}
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver,
userHandle, /* parent */ false);
@@ -7213,6 +7220,8 @@
mUserManager.setUserRestriction(
UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false,
UserHandle.SYSTEM);
+ mUserManager.setUserRestriction(
+ UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM);
// Device-wide policies set by the profile owner need to be cleaned up here.
mLockPatternUtils.setDeviceOwnerInfo(null);
@@ -11957,10 +11966,21 @@
}
private void showLocationSettingsChangedNotification(UserHandle user) {
+ Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Fill the component explicitly to prevent the PendingIntent from being intercepted
+ // and fired with crafted target. b/155183624
+ ActivityInfo targetInfo = intent.resolveActivityInfo(
+ mInjector.getPackageManager(user.getIdentifier()),
+ PackageManager.MATCH_SYSTEM_ONLY);
+ if (targetInfo != null) {
+ intent.setComponent(targetInfo.getComponentName());
+ } else {
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for location settings");
+ }
+
PendingIntent locationSettingsIntent = mInjector.pendingIntentGetActivityAsUser(mContext, 0,
- new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_UPDATE_CURRENT,
- null, user);
+ intent, PendingIntent.FLAG_UPDATE_CURRENT, null, user);
Notification notification = new Notification.Builder(mContext,
SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_info_outline)
@@ -13825,6 +13845,8 @@
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
parentUser);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true,
+ parentUser);
});
// markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
@@ -15906,15 +15928,12 @@
false /* parent */);
// DO shouldn't be able to use this method.
enforceProfileOwnerOfOrganizationOwnedDevice(admin);
- final DevicePolicyData userData =
- getUserData(getProfileParentId(mInjector.userHandleGetCallingUserId()));
- if (!userData.mAppsSuspended) {
- return PERSONAL_APPS_NOT_SUSPENDED;
- } else {
- final long deadline = admin.mProfileOffDeadline;
- return makeSuspensionReasons(admin.mSuspendPersonalApps,
- deadline != 0 && System.currentTimeMillis() > deadline);
- }
+ final long deadline = admin.mProfileOffDeadline;
+ final int result = makeSuspensionReasons(admin.mSuspendPersonalApps,
+ deadline != 0 && mInjector.systemCurrentTimeMillis() > deadline);
+ Slog.d(LOG_TAG, String.format("getPersonalAppsSuspendedReasons user: %d; result: %d",
+ mInjector.userHandleGetCallingUserId(), result));
+ return result;
}
}
@@ -15987,31 +16006,27 @@
private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension(
int profileUserId, boolean unlocked) {
final boolean suspendedExplicitly;
- final int deadlineState;
- final String poPackage;
+ final boolean suspendedByTimeout;
synchronized (getLockObject()) {
final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId);
if (profileOwner != null) {
- deadlineState =
+ final int deadlineState =
updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked);
suspendedExplicitly = profileOwner.mSuspendPersonalApps;
- poPackage = profileOwner.info.getPackageName();
+ suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED;
+ Slog.d(LOG_TAG, String.format(
+ "Personal apps suspended explicitly: %b, deadline state: %d",
+ suspendedExplicitly, deadlineState));
+ final int notificationState =
+ unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState;
+ updateProfileOffDeadlineNotificationLocked(
+ profileUserId, profileOwner, notificationState);
} else {
- poPackage = null;
suspendedExplicitly = false;
- deadlineState = PROFILE_OFF_DEADLINE_DEFAULT;
+ suspendedByTimeout = false;
}
}
- Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d",
- suspendedExplicitly, deadlineState));
-
- if (poPackage != null) {
- final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState;
- updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState);
- }
-
- final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED;
final int parentUserId = getProfileParentId(profileUserId);
suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout);
@@ -16027,8 +16042,12 @@
int profileUserId, ActiveAdmin profileOwner, boolean unlocked) {
final long now = mInjector.systemCurrentTimeMillis();
if (profileOwner.mProfileOffDeadline != 0 && now > profileOwner.mProfileOffDeadline) {
- // Profile off deadline is already reached.
- Slog.i(LOG_TAG, "Profile off deadline has been reached.");
+ Slog.i(LOG_TAG, "Profile off deadline has been reached, unlocked: " + unlocked);
+ if (profileOwner.mProfileOffDeadline != -1) {
+ // Move the deadline far to the past so that it cannot be rolled back by TZ change.
+ profileOwner.mProfileOffDeadline = -1;
+ saveSettingsLocked(profileUserId);
+ }
return PROFILE_OFF_DEADLINE_REACHED;
}
boolean shouldSaveSettings = false;
@@ -16119,9 +16138,9 @@
}
}
- private void updateProfileOffDeadlineNotification(
- int profileUserId, String profileOwnerPackage, int notificationState) {
-
+ @GuardedBy("getLockObject()")
+ private void updateProfileOffDeadlineNotificationLocked(
+ int profileUserId, ActiveAdmin profileOwner, int notificationState) {
if (notificationState == PROFILE_OFF_DEADLINE_DEFAULT) {
mInjector.getNotificationManager().cancel(SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED);
return;
@@ -16139,23 +16158,41 @@
final Notification.Action turnProfileOnButton =
new Notification.Action.Builder(null /* icon */, buttonText, pendingIntent).build();
- final String text = mContext.getString(
- notificationState == PROFILE_OFF_DEADLINE_WARNING
- ? R.string.personal_apps_suspension_tomorrow_text
- : R.string.personal_apps_suspension_text);
- final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED;
+ final String text;
+ final boolean ongoing;
+ if (notificationState == PROFILE_OFF_DEADLINE_WARNING) {
+ // Round to the closest integer number of days.
+ final int maxDays = (int)
+ ((profileOwner.mProfileMaximumTimeOffMillis + MS_PER_DAY / 2) / MS_PER_DAY);
+ final String date = DateUtils.formatDateTime(
+ mContext, profileOwner.mProfileOffDeadline, DateUtils.FORMAT_SHOW_DATE);
+ final String time = DateUtils.formatDateTime(
+ mContext, profileOwner.mProfileOffDeadline, DateUtils.FORMAT_SHOW_TIME);
+ text = mContext.getString(
+ R.string.personal_apps_suspension_soon_text, date, time, maxDays);
+ ongoing = false;
+ } else {
+ text = mContext.getString(R.string.personal_apps_suspension_text);
+ ongoing = true;
+ }
+ final int color = mContext.getColor(R.color.personal_apps_suspension_notification_color);
+ final Bundle extras = new Bundle();
+ // TODO: Create a separate string for this.
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ mContext.getString(R.string.notification_work_profile_content_description));
final Notification notification =
new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setSmallIcon(R.drawable.ic_corp_badge_no_background)
.setOngoing(ongoing)
.setAutoCancel(false)
.setContentTitle(mContext.getString(
R.string.personal_apps_suspension_title))
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setColor(color)
.addAction(turnProfileOnButton)
+ .addExtras(extras)
.build();
mInjector.getNotificationManager().notify(
SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED, notification);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index da716ea..c6871842 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -30,6 +30,7 @@
import android.os.IBinder;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.provider.Telephony;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
@@ -84,6 +85,7 @@
result.removeAll(getSystemLauncherPackages());
result.removeAll(getAccessibilityServices());
result.removeAll(getInputMethodPackages());
+ result.remove(Telephony.Sms.getDefaultSmsPackage(mContext));
result.remove(getSettingsPackageName());
final String[] unsuspendablePackages =
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 7cfbcc8..1630f27 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -22,9 +22,12 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.DateUtils;
+import android.util.Slog;
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -38,6 +41,7 @@
*/
class RemoteBugreportUtils {
+ private static final String TAG = "RemoteBugreportUtils";
static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
@Retention(RetentionPolicy.SOURCE)
@@ -60,6 +64,17 @@
Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+
+ // Fill the component explicitly to prevent the PendingIntent from being intercepted
+ // and fired with crafted target. b/155183624
+ ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
+ context.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
+ if (targetInfo != null) {
+ dialogIntent.setComponent(targetInfo.getComponentName());
+ } else {
+ Slog.wtf(TAG, "Failed to resolve intent for remote bugreport dialog");
+ }
+
PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
dialogIntent, 0, null, UserHandle.CURRENT);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index c3c2157..f0dca77 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -63,6 +63,7 @@
static constexpr auto libDir = "lib"sv;
static constexpr auto libSuffix = ".so"sv;
static constexpr auto blockSize = 4096;
+ static constexpr auto systemPackage = "android"sv;
};
static const Constants& constants() {
@@ -266,6 +267,7 @@
mIncFs(sm.getIncFs()),
mAppOpsManager(sm.getAppOpsManager()),
mJni(sm.getJni()),
+ mLooper(sm.getLooper()),
mIncrementalDir(rootDir) {
if (!mVold) {
LOG(FATAL) << "Vold service is unavailable";
@@ -276,12 +278,22 @@
if (!mAppOpsManager) {
LOG(FATAL) << "AppOpsManager is unavailable";
}
+ if (!mJni) {
+ LOG(FATAL) << "JNI is unavailable";
+ }
+ if (!mLooper) {
+ LOG(FATAL) << "Looper is unavailable";
+ }
mJobQueue.reserve(16);
mJobProcessor = std::thread([this]() {
mJni->initializeForCurrentThread();
runJobProcessing();
});
+ mCmdLooperThread = std::thread([this]() {
+ mJni->initializeForCurrentThread();
+ runCmdLooper();
+ });
const auto mountedRootNames = adoptMountedInstances();
mountExistingImages(mountedRootNames);
@@ -294,6 +306,7 @@
}
mJobCondition.notify_all();
mJobProcessor.join();
+ mCmdLooperThread.join();
}
static const char* toString(IncrementalService::BindKind kind) {
@@ -365,7 +378,8 @@
std::lock_guard l(mLock);
mounts.reserve(mMounts.size());
for (auto&& [id, ifs] : mMounts) {
- if (ifs->mountId == id) {
+ if (ifs->mountId == id &&
+ ifs->dataLoaderStub->params().packageName == Constants::systemPackage) {
mounts.push_back(ifs);
}
}
@@ -736,7 +750,7 @@
return -EINVAL;
}
- LOG(INFO) << "Removing bind point " << target;
+ LOG(INFO) << "Removing bind point " << target << " for storage " << storage;
// Here we should only look up by the exact target, not by a subdirectory of any existing mount,
// otherwise there's a chance to unmount something completely unrelated
@@ -1315,6 +1329,13 @@
return true;
}
+void IncrementalService::runCmdLooper() {
+ constexpr auto kTimeoutMsecs = 1000;
+ while (mRunning.load(std::memory_order_relaxed)) {
+ mLooper->pollAll(kTimeoutMsecs);
+ }
+}
+
IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
IncFsMount& ifs, DataLoaderParamsParcel&& params,
const DataLoaderStatusListener* externalListener) {
@@ -1337,8 +1358,9 @@
fsControlParcel.incremental->log.reset(dup(ifs.control.logs()));
fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId);
- ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params),
- std::move(fsControlParcel), externalListener);
+ ifs.dataLoaderStub =
+ new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel),
+ externalListener, path::join(ifs.root, constants().mount));
}
template <class Duration>
@@ -1658,22 +1680,31 @@
IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
DataLoaderParamsParcel&& params,
FileSystemControlParcel&& control,
- const DataLoaderStatusListener* externalListener)
+ const DataLoaderStatusListener* externalListener,
+ std::string&& healthPath)
: mService(service),
mId(id),
mParams(std::move(params)),
mControl(std::move(control)),
- mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {
+ mListener(externalListener ? *externalListener : DataLoaderStatusListener()),
+ mHealthPath(std::move(healthPath)) {
+ healthStatusOk();
}
-IncrementalService::DataLoaderStub::~DataLoaderStub() = default;
+IncrementalService::DataLoaderStub::~DataLoaderStub() {
+ if (mId != kInvalidStorageId) {
+ cleanupResources();
+ }
+}
void IncrementalService::DataLoaderStub::cleanupResources() {
requestDestroy();
auto now = Clock::now();
-
std::unique_lock lock(mMutex);
+
+ unregisterFromPendingReads();
+
mParams = {};
mControl = {};
mStatusCondition.wait_until(lock, now + 60s, [this] {
@@ -1710,21 +1741,19 @@
}
bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) {
- int oldStatus, curStatus;
{
std::unique_lock lock(mMutex);
- oldStatus = mTargetStatus;
- curStatus = mCurrentStatus;
setTargetStatusLocked(newStatus);
}
- LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
- << newStatus << " (current " << curStatus << ")";
return fsmStep();
}
void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) {
+ auto oldStatus = mTargetStatus;
mTargetStatus = status;
mTargetStatusTs = Clock::now();
+ LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
+ << status << " (current " << mCurrentStatus << ")";
}
bool IncrementalService::DataLoaderStub::bind() {
@@ -1780,6 +1809,8 @@
targetStatus = mTargetStatus;
}
+ LOG(DEBUG) << "fsmStep: " << mId << ": " << currentStatus << " -> " << targetStatus;
+
if (currentStatus == targetStatus) {
return true;
}
@@ -1797,7 +1828,7 @@
case IDataLoaderStatusListener::DATA_LOADER_STOPPED:
return start();
}
- // fallthrough
+ [[fallthrough]];
}
case IDataLoaderStatusListener::DATA_LOADER_CREATED:
switch (currentStatus) {
@@ -1841,8 +1872,8 @@
listener = mListener;
if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE) {
- // For unavailable, reset target status.
- setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE);
+ // For unavailable, unbind from DataLoader to ensure proper re-commit.
+ setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
}
}
@@ -1860,6 +1891,68 @@
return binder::Status::ok();
}
+void IncrementalService::DataLoaderStub::healthStatusOk() {
+ LOG(DEBUG) << "healthStatusOk: " << mId;
+ std::unique_lock lock(mMutex);
+ registerForPendingReads();
+}
+
+void IncrementalService::DataLoaderStub::healthStatusReadsPending() {
+ LOG(DEBUG) << "healthStatusReadsPending: " << mId;
+ requestStart();
+
+ std::unique_lock lock(mMutex);
+ unregisterFromPendingReads();
+}
+
+void IncrementalService::DataLoaderStub::healthStatusBlocked() {}
+
+void IncrementalService::DataLoaderStub::healthStatusUnhealthy() {}
+
+void IncrementalService::DataLoaderStub::registerForPendingReads() {
+ auto pendingReadsFd = mHealthControl.pendingReads();
+ if (pendingReadsFd < 0) {
+ mHealthControl = mService.mIncFs->openMount(mHealthPath);
+ pendingReadsFd = mHealthControl.pendingReads();
+ if (pendingReadsFd < 0) {
+ LOG(ERROR) << "Failed to open health control for: " << mId << ", path: " << mHealthPath
+ << "(" << mHealthControl.cmd() << ":" << mHealthControl.pendingReads() << ":"
+ << mHealthControl.logs() << ")";
+ return;
+ }
+ }
+
+ mService.mLooper->addFd(
+ pendingReadsFd, android::Looper::POLL_CALLBACK, android::Looper::EVENT_INPUT,
+ [](int, int, void* data) -> int {
+ auto&& self = (DataLoaderStub*)data;
+ return self->onPendingReads();
+ },
+ this);
+ mService.mLooper->wake();
+}
+
+void IncrementalService::DataLoaderStub::unregisterFromPendingReads() {
+ const auto pendingReadsFd = mHealthControl.pendingReads();
+ if (pendingReadsFd < 0) {
+ return;
+ }
+
+ mService.mLooper->removeFd(pendingReadsFd);
+ mService.mLooper->wake();
+
+ mHealthControl = {};
+}
+
+int IncrementalService::DataLoaderStub::onPendingReads() {
+ if (!mService.mRunning.load(std::memory_order_relaxed)) {
+ return 0;
+ }
+
+ healthStatusReadsPending();
+ return 0;
+}
+
void IncrementalService::DataLoaderStub::onDump(int fd) {
dprintf(fd, " dataLoader: {\n");
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index cf310b1..f3fde2a 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -18,6 +18,7 @@
#include <android/content/pm/BnDataLoaderStatusListener.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
+#include <android/content/pm/FileSystemControlParcel.h>
#include <android/content/pm/IDataLoaderStatusListener.h>
#include <android/os/incremental/BnIncrementalServiceConnector.h>
#include <binder/IAppOpsCallback.h>
@@ -160,7 +161,7 @@
DataLoaderStub(IncrementalService& service, MountId id,
content::pm::DataLoaderParamsParcel&& params,
content::pm::FileSystemControlParcel&& control,
- const DataLoaderStatusListener* externalListener);
+ const DataLoaderStatusListener* externalListener, std::string&& healthPath);
~DataLoaderStub();
// Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
// result in an error.
@@ -178,6 +179,10 @@
private:
binder::Status onStatusChanged(MountId mount, int newStatus) final;
+ void registerForPendingReads();
+ void unregisterFromPendingReads();
+ int onPendingReads();
+
bool isValid() const { return mId != kInvalidStorageId; }
sp<content::pm::IDataLoader> getDataLoader();
@@ -191,6 +196,16 @@
bool fsmStep();
+ // Watching for pending reads.
+ void healthStatusOk();
+ // Pending reads detected, waiting for Xsecs to confirm blocked state.
+ void healthStatusReadsPending();
+ // There are reads pending for X+secs, waiting for additional Ysecs to confirm unhealthy
+ // state.
+ void healthStatusBlocked();
+ // There are reads pending for X+Ysecs, marking storage as unhealthy.
+ void healthStatusUnhealthy();
+
IncrementalService& mService;
std::mutex mMutex;
@@ -203,6 +218,9 @@
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
TimePoint mTargetStatusTs = {};
+
+ std::string mHealthPath;
+ incfs::UniqueControl mHealthControl;
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
@@ -300,12 +318,15 @@
const incfs::FileId& libFileId, std::string_view targetLibPath,
Clock::time_point scheduledTs);
+ void runCmdLooper();
+
private:
const std::unique_ptr<VoldServiceWrapper> mVold;
const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
const std::unique_ptr<IncFsWrapper> mIncFs;
const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager;
const std::unique_ptr<JniWrapper> mJni;
+ const std::unique_ptr<LooperWrapper> mLooper;
const std::string mIncrementalDir;
mutable std::mutex mLock;
@@ -319,13 +340,16 @@
std::atomic_bool mSystemReady = false;
StorageId mNextId = 0;
+ std::atomic_bool mRunning{true};
+
using Job = std::function<void()>;
std::unordered_map<MountId, std::vector<Job>> mJobQueue;
MountId mPendingJobsMount = kInvalidStorageId;
std::condition_variable mJobCondition;
std::mutex mJobMutex;
std::thread mJobProcessor;
- bool mRunning = true;
+
+ std::thread mCmdLooperThread;
};
} // namespace android::incremental
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 85f7441..08fb486 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -113,6 +113,23 @@
JavaVM* const mJvm;
};
+class RealLooperWrapper final : public LooperWrapper {
+public:
+ int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,
+ void* data) final {
+ return mLooper.addFd(fd, ident, events, callback, data);
+ }
+ int removeFd(int fd) final { return mLooper.removeFd(fd); }
+ void wake() final { return mLooper.wake(); }
+ int pollAll(int timeoutMillis) final { return mLooper.pollAll(timeoutMillis); }
+
+private:
+ struct Looper : public android::Looper {
+ Looper() : android::Looper(/*allowNonCallbacks=*/false) {}
+ ~Looper() {}
+ } mLooper;
+};
+
class RealIncFs : public IncFsWrapper {
public:
RealIncFs() = default;
@@ -203,6 +220,10 @@
return std::make_unique<RealJniWrapper>(mJvm);
}
+std::unique_ptr<LooperWrapper> RealServiceManager::getLooper() {
+ return std::make_unique<RealLooperWrapper>();
+}
+
static JavaVM* getJavaVm(JNIEnv* env) {
CHECK(env);
JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 3792830..abbf2f4 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -26,6 +26,7 @@
#include <binder/Status.h>
#include <incfs.h>
#include <jni.h>
+#include <utils/Looper.h>
#include <memory>
#include <span>
@@ -106,6 +107,16 @@
virtual void initializeForCurrentThread() const = 0;
};
+class LooperWrapper {
+public:
+ virtual ~LooperWrapper() = default;
+ virtual int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,
+ void* data) = 0;
+ virtual int removeFd(int fd) = 0;
+ virtual void wake() = 0;
+ virtual int pollAll(int timeoutMillis) = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -114,6 +125,7 @@
virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0;
virtual std::unique_ptr<JniWrapper> getJni() = 0;
+ virtual std::unique_ptr<LooperWrapper> getLooper() = 0;
};
// --- Real stuff ---
@@ -127,6 +139,7 @@
std::unique_ptr<IncFsWrapper> getIncFs() final;
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final;
std::unique_ptr<JniWrapper> getJni() final;
+ std::unique_ptr<LooperWrapper> getLooper() final;
private:
template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 2205bfe..2e4625c 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -242,6 +242,9 @@
void setDataLoaderStatusDestroyed() {
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
}
+ void setDataLoaderStatusUnavailable() {
+ mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE);
+ }
binder::Status unbindFromDataLoaderOk(int32_t id) {
if (mDataLoader) {
if (auto status = mDataLoader->destroy(id); !status.isOk()) {
@@ -286,6 +289,14 @@
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+ void openMountSuccess() {
+ ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
+ }
+
+ static constexpr auto kPendingReadsFd = 42;
+ Control openMountForHealth(std::string_view) {
+ return UniqueControl(IncFs_CreateControl(-1, kPendingReadsFd, -1));
+ }
RawMetadata getMountInfoMetadata(const Control& control, std::string_view path) {
metadata::Mount m;
@@ -346,7 +357,42 @@
public:
MOCK_CONST_METHOD0(initializeForCurrentThread, void());
- MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(1); }
+ MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(2); }
+};
+
+class MockLooperWrapper : public LooperWrapper {
+public:
+ MOCK_METHOD5(addFd, int(int, int, int, android::Looper_callbackFunc, void*));
+ MOCK_METHOD1(removeFd, int(int));
+ MOCK_METHOD0(wake, void());
+ MOCK_METHOD1(pollAll, int(int));
+
+ MockLooperWrapper() {
+ ON_CALL(*this, addFd(_, _, _, _, _))
+ .WillByDefault(Invoke(this, &MockLooperWrapper::storeCallback));
+ ON_CALL(*this, removeFd(_)).WillByDefault(Invoke(this, &MockLooperWrapper::clearCallback));
+ ON_CALL(*this, pollAll(_)).WillByDefault(Invoke(this, &MockLooperWrapper::sleepFor));
+ }
+
+ int storeCallback(int, int, int, android::Looper_callbackFunc callback, void* data) {
+ mCallback = callback;
+ mCallbackData = data;
+ return 0;
+ }
+
+ int clearCallback(int) {
+ mCallback = nullptr;
+ mCallbackData = nullptr;
+ return 0;
+ }
+
+ int sleepFor(int timeoutMillis) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(timeoutMillis));
+ return 0;
+ }
+
+ android::Looper_callbackFunc mCallback = nullptr;
+ void* mCallbackData = nullptr;
};
class MockServiceManager : public ServiceManagerWrapper {
@@ -355,12 +401,14 @@
std::unique_ptr<MockDataLoaderManager> dataLoaderManager,
std::unique_ptr<MockIncFs> incfs,
std::unique_ptr<MockAppOpsManager> appOpsManager,
- std::unique_ptr<MockJniWrapper> jni)
+ std::unique_ptr<MockJniWrapper> jni,
+ std::unique_ptr<MockLooperWrapper> looper)
: mVold(std::move(vold)),
mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
mAppOpsManager(std::move(appOpsManager)),
- mJni(std::move(jni)) {}
+ mJni(std::move(jni)),
+ mLooper(std::move(looper)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
@@ -368,6 +416,7 @@
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
+ std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
private:
std::unique_ptr<MockVoldService> mVold;
@@ -375,6 +424,7 @@
std::unique_ptr<MockIncFs> mIncFs;
std::unique_ptr<MockAppOpsManager> mAppOpsManager;
std::unique_ptr<MockJniWrapper> mJni;
+ std::unique_ptr<MockLooperWrapper> mLooper;
};
// --- IncrementalServiceTest ---
@@ -394,13 +444,16 @@
mAppOpsManager = appOps.get();
auto jni = std::make_unique<NiceMock<MockJniWrapper>>();
mJni = jni.get();
+ auto looper = std::make_unique<NiceMock<MockLooperWrapper>>();
+ mLooper = looper.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
std::move(
dataloaderManager),
std::move(incFs),
std::move(appOps),
- std::move(jni)),
+ std::move(jni),
+ std::move(looper)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
@@ -430,12 +483,13 @@
}
protected:
- NiceMock<MockVoldService>* mVold;
- NiceMock<MockIncFs>* mIncFs;
- NiceMock<MockDataLoaderManager>* mDataLoaderManager;
- NiceMock<MockAppOpsManager>* mAppOpsManager;
- NiceMock<MockJniWrapper>* mJni;
- NiceMock<MockDataLoader>* mDataLoader;
+ NiceMock<MockVoldService>* mVold = nullptr;
+ NiceMock<MockIncFs>* mIncFs = nullptr;
+ NiceMock<MockDataLoaderManager>* mDataLoaderManager = nullptr;
+ NiceMock<MockAppOpsManager>* mAppOpsManager = nullptr;
+ NiceMock<MockJniWrapper>* mJni = nullptr;
+ NiceMock<MockLooperWrapper>* mLooper = nullptr;
+ NiceMock<MockDataLoader>* mDataLoader = nullptr;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
DataLoaderParamsParcel mDataLoaderParcel;
@@ -593,6 +647,54 @@
mDataLoaderManager->setDataLoaderStatusCreated();
}
+TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoader->initializeCreateOkNoStatus();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ mDataLoaderManager->setDataLoaderStatusUnavailable();
+}
+
+TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mIncFs->openMountSuccess();
+ mVold->bindMountSuccess();
+ mDataLoader->initializeCreateOkNoStatus();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(2);
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ mDataLoaderManager->setDataLoaderStatusUnavailable();
+ ASSERT_NE(nullptr, mLooper->mCallback);
+ ASSERT_NE(nullptr, mLooper->mCallbackData);
+ mLooper->mCallback(-1, -1, mLooper->mCallbackData);
+}
+
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0fc333f..2a200fb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -590,7 +590,6 @@
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
- SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
@@ -1891,6 +1890,10 @@
|| mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
t.traceBegin("StartTvInputManager");
mSystemServiceManager.startService(TvInputManagerService.class);
+ t.traceEnd();
+ }
+
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_TUNER)) {
t.traceBegin("StartTunerResourceManager");
mSystemServiceManager.startService(TunerResourceManagerService.class);
t.traceEnd();
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index f8d197a..d78dad5 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -46,6 +46,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.os.Process;
import android.os.UserHandle;
@@ -106,6 +107,7 @@
new CrossProfileAppsServiceImpl(mContext, mInjector);
private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
+ private final Set<Integer> mKilledUids = new HashSet<>();
@Mock private PackageManagerInternal mPackageManagerInternal;
@Mock private IPackageManager mIPackageManager;
@@ -389,6 +391,33 @@
}
@Test
+ public void setInteractAcrossProfilesAppOp_toAllowed_doesNotKillApp() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(mKilledUids).isEmpty();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toDisallowed_killsAppsInBothProfiles() {
+ shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_DEFAULT);
+
+ assertThat(mKilledUids).contains(WORK_PROFILE_UID);
+ assertThat(mKilledUids).contains(PERSONAL_PROFILE_UID);
+ }
+
+ private PermissionInfo createCrossProfilesPermissionInfo() {
+ PermissionInfo permissionInfo = new PermissionInfo();
+ permissionInfo.name = Manifest.permission.INTERACT_ACROSS_PROFILES;
+ permissionInfo.protectionLevel = PermissionInfo.PROTECTION_FLAG_APPOP;
+ return permissionInfo;
+ }
+
+ @Test
public void canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse() {
mockUninstallCrossProfileAppFromWorkProfile();
assertThat(mCrossProfileAppsServiceImpl
@@ -678,5 +707,10 @@
// ShadowActivityThread with Robolectric. This method is currently not supported there.
return mContext.checkPermission(permission, Process.myPid(), uid);
}
+
+ @Override
+ public void killUid(String packageName, int uid) {
+ mKilledUids.add(uid);
+ }
}
}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 270a3b5..3b38d94 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -79,6 +79,7 @@
<uses-permission android:name="android.permission.READ_DREAM_STATE"/>
<uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 2ce70b6f..b6cf278 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -129,8 +129,11 @@
public void bind_requestsContextToBindService() {
mConnection.bindLocked();
verify(mMockContext).bindServiceAsUser(any(Intent.class), eq(mConnection),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS), any(UserHandle.class));
+ eq(Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
+ | Context.BIND_INCLUDE_CAPABILITIES),
+ any(UserHandle.class));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index d292526..285caf3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -186,7 +186,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -269,7 +270,8 @@
eq(false) /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -407,7 +409,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
// Hardware authenticated
final byte[] HAT = generateRandomHAT();
@@ -462,7 +465,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -610,7 +614,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
anyString(),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -711,7 +716,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -1207,7 +1213,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
// Requesting strong and credential, when credential is setup
resetReceiver();
@@ -1227,7 +1234,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
// Un-downgrading the authenticator allows successful strong auth
for (BiometricService.AuthenticatorWrapper wrapper : mBiometricService.mAuthenticators) {
@@ -1250,7 +1258,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test(expected = IllegalStateException.class)
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 6b36bc5..724048b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -204,7 +204,7 @@
// Notification title and text for setManagedProfileMaximumTimeOff tests:
private static final String PROFILE_OFF_SUSPENSION_TITLE = "suspension_title";
private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text";
- private static final String PROFILE_OFF_SUSPENSION_TOMORROW_TEXT = "suspension_tomorrow_text";
+ private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text";
@Override
protected void setUp() throws Exception {
@@ -1998,7 +1998,6 @@
private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
Sets.newSet(
UserManager.DISALLOW_CONFIG_DATE_TIME,
- UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_BLUETOOTH_SHARING,
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -4005,6 +4004,12 @@
// Any caller should be able to call this method.
assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
+
+ verify(getServices().userManager).setUserRestriction(
+ eq(UserManager.DISALLOW_ADD_USER),
+ eq(true),
+ eq(UserHandle.of(UserHandle.USER_SYSTEM)));
+
assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
// A random caller from another user should also be able to get the right result.
@@ -4012,6 +4017,35 @@
assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
}
+ public void testMarkOrganizationOwnedDevice_baseRestrictionsAdded() throws Exception {
+ addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);
+
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
+
+ // Base restriction DISALLOW_REMOVE_MANAGED_PROFILE added
+ verify(getServices().userManager).setUserRestriction(
+ eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
+ eq(true),
+ eq(UserHandle.of(UserHandle.USER_SYSTEM)));
+
+ // Base restriction DISALLOW_ADD_USER added
+ verify(getServices().userManager).setUserRestriction(
+ eq(UserManager.DISALLOW_ADD_USER),
+ eq(true),
+ eq(UserHandle.of(UserHandle.USER_SYSTEM)));
+
+ // Assert base restrictions cannot be added or removed by admin
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE));
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.clearUserRestriction(admin1,
+ UserManager.DISALLOW_REMOVE_MANAGED_PROFILE));
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER));
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER));
+ }
+
public void testSetTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -6297,7 +6331,7 @@
// Now the user should see a warning notification.
verify(getServices().notificationManager, times(1))
.notify(anyInt(), argThat(hasExtra(EXTRA_TITLE, PROFILE_OFF_SUSPENSION_TITLE,
- EXTRA_TEXT, PROFILE_OFF_SUSPENSION_TOMORROW_TEXT)));
+ EXTRA_TEXT, PROFILE_OFF_SUSPENSION_SOON_TEXT)));
// Apps shouldn't be suspended yet.
verifyZeroInteractions(getServices().ipackageManager);
clearInvocations(getServices().alarmManager);
@@ -6407,6 +6441,16 @@
verify(mContext.spiedContext).startActivityAsUser(
MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
MockUtils.checkUserHandle(CALLER_USER_HANDLE));
+
+ // Verify that correct suspension reason is reported to the DPC.
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ assertThat(dpm.getPersonalAppsSuspendedReasons(admin1))
+ .isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);
+
+ // Verify that rolling time back doesn't change the status.
+ dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_START);
+ assertThat(dpm.getPersonalAppsSuspendedReasons(admin1))
+ .isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);
}
private void sendBroadcastWithUser(String action, int userHandle) throws Exception {
@@ -6438,7 +6482,7 @@
// To allow creation of Notification via Notification.Builder
mContext.applicationInfo = mRealTestContext.getApplicationInfo();
- // Setup notification titles.
+ // Setup resources to render notification titles and texts.
when(mServiceContext.resources
.getString(R.string.personal_apps_suspension_title))
.thenReturn(PROFILE_OFF_SUSPENSION_TITLE);
@@ -6446,14 +6490,19 @@
.getString(R.string.personal_apps_suspension_text))
.thenReturn(PROFILE_OFF_SUSPENSION_TEXT);
when(mServiceContext.resources
- .getString(R.string.personal_apps_suspension_tomorrow_text))
- .thenReturn(PROFILE_OFF_SUSPENSION_TOMORROW_TEXT);
+ .getString(eq(R.string.personal_apps_suspension_soon_text),
+ anyString(), anyString(), anyInt()))
+ .thenReturn(PROFILE_OFF_SUSPENSION_SOON_TEXT);
+
+ // Make locale available for date formatting:
+ when(mServiceContext.resources.getConfiguration())
+ .thenReturn(mRealTestContext.getResources().getConfiguration());
clearInvocations(getServices().ipackageManager);
}
private static Matcher<Notification> hasExtra(String... extras) {
- assertEquals("Odd numebr of extra key-values", 0, extras.length % 2);
+ assertEquals("Odd number of extra key-values", 0, extras.length % 2);
return new BaseMatcher<Notification>() {
@Override
public boolean matches(Object item) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index bbd4472..b306ff0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -226,6 +226,14 @@
uh.userType = type;
uh.profileGroupId = profileGroupId;
when(userManager.getUserInfo(eq(userId))).thenReturn(uh);
+ // Ensure there are no duplicate UserInfo records.
+ // TODO: fix tests so that this is not needed.
+ for (int i = 0; i < mUserInfos.size(); i++) {
+ if (mUserInfos.get(i).id == userId) {
+ mUserInfos.remove(i);
+ break;
+ }
+ }
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 8137c36..43a396d 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.Handler;
@@ -28,6 +29,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.display.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
import com.android.server.display.DisplayModeDirector.Vote;
@@ -36,6 +38,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@@ -52,16 +55,15 @@
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
}
- private DisplayModeDirector createDisplayModeDirectorWithDisplayFpsRange(
- int minFps, int maxFps) {
+ private DisplayModeDirector createDirectorFromRefreshRateArray(
+ float[] refreshRates, int baseModeId) {
DisplayModeDirector director =
new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
int displayId = 0;
- int numModes = maxFps - minFps + 1;
- Display.Mode[] modes = new Display.Mode[numModes];
- for (int i = minFps; i <= maxFps; i++) {
- modes[i - minFps] = new Display.Mode(
- /*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
+ Display.Mode[] modes = new Display.Mode[refreshRates.length];
+ for (int i = 0; i < refreshRates.length; i++) {
+ modes[i] = new Display.Mode(
+ /*modeId=*/baseModeId + i, /*width=*/1000, /*height=*/1000, refreshRates[i]);
}
SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
supportedModesByDisplay.put(displayId, modes);
@@ -72,14 +74,22 @@
return director;
}
+ private DisplayModeDirector createDirectorFromFpsRange(int minFps, int maxFps) {
+ int numRefreshRates = maxFps - minFps + 1;
+ float[] refreshRates = new float[numRefreshRates];
+ for (int i = 0; i < numRefreshRates; i++) {
+ refreshRates[i] = minFps + i;
+ }
+ return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps);
+ }
+
@Test
public void testDisplayModeVoting() {
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
DesiredDisplayModeSpecs modeSpecs =
- createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
- displayId);
+ createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(displayId);
Truth.assertThat(modeSpecs.baseModeId).isEqualTo(60);
Truth.assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(0f);
Truth.assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(Float.POSITIVE_INFINITY);
@@ -92,7 +102,7 @@
{
int minFps = 60;
int maxFps = 90;
- DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
assertTrue(2 * numPriorities < maxFps - minFps + 1);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -114,7 +124,7 @@
// presence of higher priority votes.
{
assertTrue(numPriorities >= 2);
- DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
@@ -131,7 +141,7 @@
@Test
public void testVotingWithFloatingPointErrors() {
int displayId = 0;
- DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(50, 90);
+ DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
@@ -154,7 +164,7 @@
assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE);
int displayId = 0;
- DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
@@ -202,7 +212,7 @@
>= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
int displayId = 0;
- DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
@@ -235,4 +245,61 @@
.isWithin(FLOAT_TOLERANCE)
.of(75);
}
+
+ void verifySpecsWithRefreshRateSettings(DisplayModeDirector director, float minFps,
+ float peakFps, float defaultFps, float primaryMin, float primaryMax,
+ float appRequestMin, float appRequestMax) {
+ DesiredDisplayModeSpecs specs = director.getDesiredDisplayModeSpecsWithInjectedFpsSettings(
+ minFps, peakFps, defaultFps);
+ Truth.assertThat(specs.primaryRefreshRateRange.min).isEqualTo(primaryMin);
+ Truth.assertThat(specs.primaryRefreshRateRange.max).isEqualTo(primaryMax);
+ Truth.assertThat(specs.appRequestRefreshRateRange.min).isEqualTo(appRequestMin);
+ Truth.assertThat(specs.appRequestRefreshRateRange.max).isEqualTo(appRequestMax);
+ }
+
+ @Test
+ public void testSpecsFromRefreshRateSettings() {
+ // Confirm that, with varying settings for min, peak, and default refresh rate,
+ // DesiredDisplayModeSpecs is calculated correctly.
+ float[] refreshRates = {30.f, 60.f, 90.f, 120.f, 150.f};
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/0);
+
+ float inf = Float.POSITIVE_INFINITY;
+ verifySpecsWithRefreshRateSettings(director, 0, 0, 0, 0, inf, 0, inf);
+ verifySpecsWithRefreshRateSettings(director, 0, 0, 90, 0, 90, 0, inf);
+ verifySpecsWithRefreshRateSettings(director, 0, 90, 0, 0, 90, 0, 90);
+ verifySpecsWithRefreshRateSettings(director, 0, 90, 60, 0, 60, 0, 90);
+ verifySpecsWithRefreshRateSettings(director, 0, 90, 120, 0, 90, 0, 90);
+ verifySpecsWithRefreshRateSettings(director, 90, 0, 0, 90, inf, 0, inf);
+ verifySpecsWithRefreshRateSettings(director, 90, 0, 120, 90, 120, 0, inf);
+ verifySpecsWithRefreshRateSettings(director, 90, 0, 60, 90, inf, 0, inf);
+ verifySpecsWithRefreshRateSettings(director, 90, 120, 0, 90, 120, 0, 120);
+ verifySpecsWithRefreshRateSettings(director, 90, 60, 0, 90, 90, 0, 90);
+ verifySpecsWithRefreshRateSettings(director, 60, 120, 90, 60, 90, 0, 120);
+ }
+
+ void verifyBrightnessObserverCall(DisplayModeDirector director, float minFps, float peakFps,
+ float defaultFps, float brightnessObserverMin, float brightnessObserverMax) {
+ BrightnessObserver brightnessObserver = Mockito.mock(BrightnessObserver.class);
+ director.injectBrightnessObserver(brightnessObserver);
+ director.getDesiredDisplayModeSpecsWithInjectedFpsSettings(minFps, peakFps, defaultFps);
+ verify(brightnessObserver)
+ .onRefreshRateSettingChangedLocked(brightnessObserverMin, brightnessObserverMax);
+ }
+
+ @Test
+ public void testBrightnessObserverCallWithRefreshRateSettings() {
+ // Confirm that, with varying settings for min, peak, and default refresh rate, we make the
+ // correct call to the brightness observer.
+ float[] refreshRates = {60.f, 90.f, 120.f};
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/0);
+ verifyBrightnessObserverCall(director, 0, 0, 0, 0, 0);
+ verifyBrightnessObserverCall(director, 0, 0, 90, 0, 90);
+ verifyBrightnessObserverCall(director, 0, 90, 0, 0, 90);
+ verifyBrightnessObserverCall(director, 0, 90, 60, 0, 60);
+ verifyBrightnessObserverCall(director, 90, 90, 0, 90, 90);
+ verifyBrightnessObserverCall(director, 120, 90, 0, 120, 90);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index e79b5af..a2393a8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -32,8 +32,10 @@
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
@@ -692,5 +694,17 @@
String permission, int uid, int owningUid, boolean exported) {
return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
}
+
+ @Override
+ public void killUid(String packageName, int uid) {
+ try {
+ ActivityManager.getService().killApplication(
+ packageName,
+ UserHandle.getAppId(uid),
+ UserHandle.getUserId(uid),
+ PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED);
+ } catch (RemoteException ignored) {
+ }
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index d4edab4..63d797e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -178,6 +178,7 @@
/* files */ null,
/* prepared */ true,
/* committed */ true,
+ /* destroyed */ staged ? true : false,
/* sealed */ false, // Setting to true would trigger some PM logic.
/* childSessionIds */ childSessionIds != null ? childSessionIds : new int[0],
/* parentSessionId */ parentSessionId,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index daaf870..b0b5386 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -154,18 +154,7 @@
@Test
public void test_serializePackage() throws Exception {
- try (PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir,
- new PackageParser2.Callback() {
- @Override
- public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return true;
- }
-
- @Override
- public boolean hasFeature(String feature) {
- return false;
- }
- })) {
+ try (PackageParser2 pp = PackageParser2.forParsingFileWithDefaults()) {
ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
true /* useCaches */);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index efa25bd..320dacf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1582,6 +1582,41 @@
"s2");
}
+ public void testCachedShortcuts_canPassShortcutLimit() {
+ // Change the max number of shortcuts.
+ mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=4");
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"),
+ makeLongLivedShortcut("s4"))));
+ });
+
+ // Cache All
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
+ HANDLE_USER_0);
+ });
+
+ setCaller(CALLING_PACKAGE_1);
+
+ // Get dynamic shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
+ "s1", "s2", "s3", "s4");
+ // Get cached shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s1", "s2", "s3", "s4");
+
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("sx1", "sx2", "sx3", "sx4")));
+
+ // Get dynamic shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
+ "sx1", "sx2", "sx3", "sx4");
+ // Get cached shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s1", "s2", "s3", "s4");
+ }
+
// === Test for launcher side APIs ===
public void testGetShortcuts() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index d136614..6c1c019 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -22,10 +22,14 @@
import android.os.Parcelable;
import android.os.UserHandle;
import android.os.UserManager;
+import android.support.test.uiautomator.UiDevice;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
import android.util.AtomicFile;
+import androidx.test.InstrumentationRegistry;
+
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
@@ -74,6 +78,14 @@
assertEquals(accountName, um.getUserAccount(tempUserId));
}
+ public void testUserSystemPackageWhitelist() throws Exception {
+ String cmd = "cmd user report-system-user-package-whitelist-problems --critical-only";
+ final String result = runShellCommand(cmd);
+ if (!TextUtils.isEmpty(result)) {
+ fail("Command '" + cmd + " reported errors:\n" + result);
+ }
+ }
+
private Bundle createBundle() {
Bundle result = new Bundle();
// Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
@@ -118,4 +130,8 @@
assertEquals(1, childBundle.getInt("bundle_int"));
}
+ private static String runShellCommand(String cmd) throws Exception {
+ return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ .executeShellCommand(cmd);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 6b3ee5a..44bb58f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -347,6 +347,10 @@
final int badgeIndex = userInfo.profileBadge;
assertThat(mUserManager.getUserBadgeColor(userId)).isEqualTo(
Resources.getSystem().getColor(userTypeDetails.getBadgeColor(badgeIndex), null));
+ assertThat(mUserManager.getUserBadgeDarkColor(userId)).isEqualTo(
+ Resources.getSystem().getColor(userTypeDetails.getDarkThemeBadgeColor(badgeIndex),
+ null));
+
assertThat(mUserManager.getBadgedLabelForUser("Test", asHandle(userId))).isEqualTo(
Resources.getSystem().getString(userTypeDetails.getBadgeLabel(badgeIndex), "Test"));
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 3888ff3..caa8ae5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -28,8 +28,13 @@
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.FileUtils;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -208,9 +213,12 @@
throws IOException, PackageParserException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
File dm = createDexMetadataFile("install_split_base.apk");
- PackageParser.PackageLite pkg = new PackageParser().parsePackageLite(mTmpDir,
- 0 /* flags */);
-
+ ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ ParseTypeImpl.forDefaultParsing().reset(), mTmpDir, 0 /* flags */);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+ PackageParser.PackageLite pkg = result.getResult();
Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkg));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 6de08fd..086c845 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -30,10 +30,8 @@
import android.content.pm.ProviderInfo
import android.os.Debug
import android.os.Environment
-import android.os.ServiceManager
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.compat.IPlatformCompat
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -63,27 +61,7 @@
setCallback { false /* hasFeature */ }
}
- private val platformCompat = IPlatformCompat.Stub
- .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE))
-
- protected val packageParser2 = PackageParser2(null /* separateProcesses */,
- false /* onlyCoreApps */, context.resources.displayMetrics, null /* cacheDir */,
- object : PackageParser2.Callback() {
- override fun isChangeEnabled(
- changeId: Long,
- appInfo: ApplicationInfo
- ): Boolean {
- // This test queries PlatformCompat because prebuilts in the tree
- // may not be updated to be compliant with the latest enforcement checks.
- return platformCompat.isChangeEnabled(changeId, appInfo)
- }
-
- // Assume the device doesn't support anything. This will affect permission
- // parsing and will force <uses-permission/> declarations to include all
- // requiredNotFeature permissions and exclude all requiredFeature permissions.
- // This mirrors the old behavior.
- override fun hasFeature(feature: String) = false
- })
+ protected val packageParser2 = PackageParser2.forParsingFileWithDefaults()
/**
* It would be difficult to mock all possibilities, so just use the APKs on device.
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 939b7a0..bb223b3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -29,8 +29,12 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedComponent;
import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.result.ParseResult;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
@@ -518,10 +522,15 @@
apexInfo.versionCode = 191000070;
int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
- PackageParser pp = new PackageParser();
- PackageParser.Package p = pp.parsePackage(apexFile, flags, false);
- PackageParser.collectCertificates(p, false);
- PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(apexFile,
+ flags, false /*collectCertificates*/);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+
+ ParsingPackage pkg = result.getResult();
+ pkg.setSigningDetails(ParsingPackageUtils.getSigningDetails(pkg, false));
+ PackageInfo pi = PackageInfoWithoutStateUtils.generate(pkg, apexInfo, flags);
assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
assertTrue(pi.applicationInfo.enabled);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index 2248707..d8910de 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -64,20 +64,6 @@
}
}
- private val parsingCallback = object : ParsingPackageUtils.Callback {
- override fun hasFeature(feature: String?) = true
-
- override fun startParsingPackage(
- packageName: String,
- baseCodePath: String,
- codePath: String,
- manifestArray: TypedArray,
- isCoreApp: Boolean
- ): ParsingPackage {
- return ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray)
- }
- }
-
@get:Rule
val tempFolder = TemporaryFolder(context.filesDir)
@@ -144,6 +130,7 @@
input.copyTo(output)
}
}
- return ParsingPackageUtils.parseDefaultOneTime(file, 0, inputCallback, parsingCallback)
+ return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/,
+ false /*collectCertificates*/)
}
}
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 21af356..f934323 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -64,6 +64,7 @@
private Context mContextSpy;
@Mock private ITvInputManager mITvInputManagerMock;
private TunerResourceManagerService mTunerResourceManagerService;
+ private boolean mIsForeground;
private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub {
boolean mReclaimed;
@@ -104,7 +105,12 @@
TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager);
- mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy);
+ mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) {
+ @Override
+ protected boolean isForeground(int pid) {
+ return mIsForeground;
+ }
+ };
mTunerResourceManagerService.onStart(true /*isForTesting*/);
}
@@ -737,4 +743,22 @@
.isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(desHandle[0])).isEqualTo(0);
}
+
+ @Test
+ public void isHigherPriorityTest() {
+ mIsForeground = false;
+ ResourceClientProfile backgroundPlaybackProfile =
+ new ResourceClientProfile(null /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+ ResourceClientProfile backgroundRecordProfile =
+ new ResourceClientProfile(null /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
+ int backgroundPlaybackPriority = mTunerResourceManagerService.getClientPriority(
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 0);
+ int backgroundRecordPriority = mTunerResourceManagerService.getClientPriority(
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD, 0);
+ assertThat(mTunerResourceManagerService.isHigherPriorityInternal(backgroundPlaybackProfile,
+ backgroundRecordProfile)).isEqualTo(
+ (backgroundPlaybackPriority > backgroundRecordPriority));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index 0e48e7e..e86399e 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -171,7 +171,7 @@
final Uri uri = Uri.parse("content://" + PKG_COMPLEX + "/");
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
- .addFlags(FLAG_READ);
+ .addFlags(FLAG_READ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
assertNull(mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
intent, intent.getFlags(), null, USER_PRIMARY));
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 39062f0..2d45f9e 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -63,6 +63,7 @@
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -107,6 +108,10 @@
private static final int UID_1 = 10000;
private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
private static final int UID_EXEMPTED_1 = 10001;
+ private static final String PACKAGE_SYSTEM_HEADFULL = "com.example.system.headfull";
+ private static final int UID_SYSTEM_HEADFULL = 10002;
+ private static final String PACKAGE_SYSTEM_HEADLESS = "com.example.system.headless";
+ private static final int UID_SYSTEM_HEADLESS = 10003;
private static final int USER_ID = 0;
private static final int USER_ID2 = 10;
private static final UserHandle USER_HANDLE_USER2 = new UserHandle(USER_ID2);
@@ -165,6 +170,7 @@
long mElapsedRealtime;
boolean mIsAppIdleEnabled = true;
boolean mIsCharging;
+ boolean mIsRestrictedBucketEnabled = true;
List<String> mNonIdleWhitelistApps = new ArrayList<>();
boolean mDisplayOn;
DisplayManager.DisplayListener mDisplayListener;
@@ -212,6 +218,11 @@
}
@Override
+ boolean isRestrictedBucketEnabled() {
+ return mIsRestrictedBucketEnabled;
+ }
+
+ @Override
File getDataSystemDirectory() {
return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
}
@@ -299,18 +310,33 @@
pie.packageName = PACKAGE_EXEMPTED_1;
packages.add(pie);
+ PackageInfo pis = new PackageInfo();
+ pis.activities = new ActivityInfo[]{mock(ActivityInfo.class)};
+ pis.applicationInfo = new ApplicationInfo();
+ pis.applicationInfo.uid = UID_SYSTEM_HEADFULL;
+ pis.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ pis.packageName = PACKAGE_SYSTEM_HEADFULL;
+ packages.add(pis);
+
+ PackageInfo pish = new PackageInfo();
+ pish.applicationInfo = new ApplicationInfo();
+ pish.applicationInfo.uid = UID_SYSTEM_HEADLESS;
+ pish.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ pish.packageName = PACKAGE_SYSTEM_HEADLESS;
+ packages.add(pish);
+
doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
try {
- doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt());
- doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
- doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
- anyInt());
- doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
- anyInt(), anyInt());
- doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
- anyInt());
- doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
- anyInt());
+ for (int i = 0; i < packages.size(); ++i) {
+ PackageInfo pkg = packages.get(i);
+
+ doReturn(pkg.applicationInfo.uid).when(mockPm)
+ .getPackageUidAsUser(eq(pkg.packageName), anyInt());
+ doReturn(pkg.applicationInfo.uid).when(mockPm)
+ .getPackageUidAsUser(eq(pkg.packageName), anyInt(), anyInt());
+ doReturn(pkg.applicationInfo).when(mockPm)
+ .getApplicationInfo(eq(pkg.packageName), anyInt());
+ }
} catch (PackageManager.NameNotFoundException nnfe) {}
}
@@ -361,34 +387,92 @@
@Test
public void testBoundWidgetPackageExempt() throws Exception {
assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
- assertEquals(STANDBY_BUCKET_EXEMPTED,
+ assertEquals(STANDBY_BUCKET_ACTIVE,
mController.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
mInjector.mElapsedRealtime, false));
}
+ private static class TestParoleListener extends AppIdleStateChangeListener {
+ private boolean mIsParoleOn = false;
+ private CountDownLatch mLatch;
+ private boolean mIsExpecting = false;
+ private boolean mExpectedParoleState;
+
+ boolean getParoleState() {
+ synchronized (this) {
+ return mIsParoleOn;
+ }
+ }
+
+ void rearmLatch(boolean expectedParoleState) {
+ synchronized (this) {
+ mLatch = new CountDownLatch(1);
+ mIsExpecting = true;
+ mExpectedParoleState = expectedParoleState;
+ }
+ }
+
+ void awaitOnLatch(long time) throws Exception {
+ mLatch.await(time, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
+ int bucket, int reason) {
+ }
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ synchronized (this) {
+ // Only record information if it is being looked for
+ if (mLatch != null && mLatch.getCount() > 0) {
+ mIsParoleOn = isParoleOn;
+ if (mIsExpecting && isParoleOn == mExpectedParoleState) {
+ mLatch.countDown();
+ }
+ }
+ }
+ }
+ }
+
@Test
public void testIsAppIdle_Charging() throws Exception {
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+
setChargingState(mController, false);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
REASON_MAIN_FORCED_BY_SYSTEM);
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ assertFalse(mController.isInParole());
+ paroleListener.rearmLatch(true);
setChargingState(mController, true);
+ paroleListener.awaitOnLatch(2000);
+ assertTrue(paroleListener.getParoleState());
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ assertTrue(mController.isInParole());
+ paroleListener.rearmLatch(false);
setChargingState(mController, false);
+ paroleListener.awaitOnLatch(2000);
+ assertFalse(paroleListener.getParoleState());
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ assertFalse(mController.isInParole());
}
@Test
public void testIsAppIdle_Enabled() throws Exception {
setChargingState(mController, false);
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+
setAppIdleEnabled(mController, true);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
REASON_MAIN_FORCED_BY_SYSTEM);
@@ -396,11 +480,17 @@
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ paroleListener.rearmLatch(false);
setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(2000);
+ assertTrue(paroleListener.mIsParoleOn);
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ paroleListener.rearmLatch(true);
setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(2000);
+ assertFalse(paroleListener.getParoleState());
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
@@ -444,7 +534,15 @@
}
private void assertBucket(int bucket) {
- assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
+ assertBucket(bucket, PACKAGE_1);
+ }
+
+ private void assertBucket(int bucket, String pkg) {
+ assertEquals(bucket, getStandbyBucket(mController, pkg));
+ }
+
+ private void assertNotBucket(int bucket) {
+ assertNotEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
}
@Test
@@ -882,6 +980,48 @@
}
@Test
+ public void testRestrictedBucketDisabled() {
+ mInjector.mIsRestrictedBucketEnabled = false;
+ // Get the controller to read the new value. Capturing the ContentObserver isn't possible
+ // at the moment.
+ mController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
+ mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
+
+ // Nothing should be able to put it into the RESTRICTED bucket.
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_TIMEOUT);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_PREDICTED);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_SYSTEM);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_USER);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ }
+
+ @Test
+ public void testRestrictedBucket_EnabledToDisabled() {
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
+ mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_SYSTEM);
+ assertBucket(STANDBY_BUCKET_RESTRICTED);
+
+ mInjector.mIsRestrictedBucketEnabled = false;
+ // Get the controller to read the new value. Capturing the ContentObserver isn't possible
+ // at the moment.
+ mController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mController.checkIdleStates(USER_ID);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ }
+
+ @Test
public void testPredictionRaiseFromRestrictedTimeout_highBucket() {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1346,6 +1486,32 @@
assertBucket(STANDBY_BUCKET_RESTRICTED);
}
+ @Test
+ public void testSystemHeadlessAppElevated() {
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
+ PACKAGE_SYSTEM_HEADFULL);
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
+ PACKAGE_SYSTEM_HEADLESS);
+ mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
+
+
+ mController.setAppStandbyBucket(PACKAGE_SYSTEM_HEADFULL, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_TIMEOUT);
+ assertBucket(STANDBY_BUCKET_RARE, PACKAGE_SYSTEM_HEADFULL);
+
+ // Make sure headless system apps don't get lowered.
+ mController.setAppStandbyBucket(PACKAGE_SYSTEM_HEADLESS, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_TIMEOUT);
+ assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_SYSTEM_HEADLESS);
+
+ // Package 1 doesn't have activities and is headless, but is not a system app, so it can
+ // be lowered.
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_TIMEOUT);
+ assertBucket(STANDBY_BUCKET_RARE, PACKAGE_1);
+ }
+
private String getAdminAppsStr(int userId) {
return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
index 5d849c1..2be3f1e8 100644
--- a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
@@ -19,6 +19,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
import android.app.usage.UsageEvents;
import android.content.res.Configuration;
@@ -26,9 +27,12 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.ArrayUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.lang.reflect.Field;
import java.util.Locale;
@RunWith(AndroidJUnit4.class)
@@ -191,4 +195,27 @@
assertTrue(intervalStats.events.size() > NUMBER_OF_EVENTS - NUMBER_OF_EVENTS_PER_PACKAGE);
assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES);
}
+
+ // All fields in this list are defined in IntervalStats and persisted - please ensure they're
+ // defined correctly in both usagestatsservice.proto and usagestatsservice_v2.proto
+ private static final String[] INTERVALSTATS_PERSISTED_FIELDS = {"beginTime", "endTime",
+ "mStringCache", "majorVersion", "minorVersion", "interactiveTracker",
+ "nonInteractiveTracker", "keyguardShownTracker", "keyguardHiddenTracker",
+ "packageStats", "configurations", "activeConfiguration", "events"};
+ // All fields in this list are defined in IntervalStats but not persisted
+ private static final String[] INTERVALSTATS_IGNORED_FIELDS = {"lastTimeSaved",
+ "packageStatsObfuscated", "CURRENT_MAJOR_VERSION", "CURRENT_MINOR_VERSION", "TAG"};
+
+ @Test
+ public void testIntervalStatsFieldsAreKnown() {
+ final IntervalStats stats = new IntervalStats();
+ final Field[] fields = stats.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ if (!(ArrayUtils.contains(INTERVALSTATS_PERSISTED_FIELDS, field.getName())
+ || ArrayUtils.contains(INTERVALSTATS_IGNORED_FIELDS, field.getName()))) {
+ fail("Found an unknown field: " + field.getName() + ". Please correctly update "
+ + "either INTERVALSTATS_PERSISTED_FIELDS or INTERVALSTATS_IGNORED_FIELDS.");
+ }
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index df92b6e..3062584 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -31,6 +31,7 @@
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteException;
+import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.server.twilight.TwilightManager;
@@ -54,6 +55,7 @@
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -144,7 +146,8 @@
addLocalService(PowerManagerInternal.class, mLocalPowerManager);
addLocalService(TwilightManager.class, mTwilightManager);
- mUiManagerService = new UiModeManagerService(mContext);
+ mUiManagerService = new UiModeManagerService(mContext, true,
+ mTwilightManager);
try {
mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
} catch (SecurityException e) {/* ignore for permission denial */}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
index 3c2d550..182bf94 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -41,6 +41,7 @@
protected static final String PKG_N_MR1 = "com.example.n_mr1";
protected static final String PKG_O = "com.example.o";
protected static final String PKG_P = "com.example.p";
+ protected static final String PKG_R = "com.example.r";
@Rule
public final TestableContext mContext =
@@ -69,6 +70,8 @@
return Build.VERSION_CODES.O;
case PKG_P:
return Build.VERSION_CODES.P;
+ case PKG_R:
+ return Build.VERSION_CODES.R;
default:
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
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 babe80e..d45ecc9 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -250,6 +250,8 @@
private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
+ private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
+
@Mock
private NotificationListeners mListeners;
@Mock private NotificationAssistants mAssistants;
@@ -471,6 +473,19 @@
mShortcutHelper.setLauncherApps(mLauncherApps);
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
+ // Pretend the shortcut exists
+ List<ShortcutInfo> shortcutInfos = new ArrayList<>();
+ ShortcutInfo info = mock(ShortcutInfo.class);
+ when(info.getPackage()).thenReturn(PKG);
+ when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
+ when(info.getUserId()).thenReturn(USER_SYSTEM);
+ when(info.isLongLived()).thenReturn(true);
+ when(info.isEnabled()).thenReturn(true);
+ shortcutInfos.add(info);
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
+ when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
+ anyString(), anyInt(), any())).thenReturn(true);
+
// Set the testable bubble extractor
RankingHelper rankingHelper = mService.getRankingHelper();
BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
@@ -704,6 +719,7 @@
)
.setActions(replyAction)
.setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setShortcutId(VALID_CONVO_SHORTCUT_ID)
.setGroupSummary(isSummary);
if (groupKey != null) {
nb.setGroup(groupKey);
@@ -6100,7 +6116,6 @@
@Test
public void testNotificationBubbles_flagRemoved_whenShortcutRemoved()
throws RemoteException {
- final String shortcutId = "someshortcutId";
setUpPrefsForBubbles(PKG, mUid,
true /* global */,
BUBBLE_PREFERENCE_ALL /* app */,
@@ -6111,27 +6126,16 @@
// Messaging notification with shortcut info
Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder(shortcutId).build();
+ new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build();
Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
null /* groupKey */, false /* isSummary */);
- nb.setShortcutId(shortcutId);
+ nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
nb.setBubbleMetadata(metadata);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- // Pretend the shortcut exists
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(PKG);
- when(info.getId()).thenReturn(shortcutId);
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
- when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
- anyString(), anyInt(), any())).thenReturn(true);
+
// Test: Send the bubble notification
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
@@ -6149,7 +6153,7 @@
// Make sure the shortcut is cached.
verify(mShortcutServiceInternal).cacheShortcuts(
- anyInt(), any(), eq(PKG), eq(Collections.singletonList(shortcutId)),
+ anyInt(), any(), eq(PKG), eq(Collections.singletonList(VALID_CONVO_SHORTCUT_ID)),
eq(USER_SYSTEM));
// Test: Remove the shortcut
@@ -6613,6 +6617,7 @@
convo2.setNotificationChannel(channel2);
convos.add(convo2);
when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
List<ConversationChannelWrapper> conversations =
mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
@@ -6640,42 +6645,64 @@
NotificationRecord nr =
generateMessageBubbleNotifRecord(mTestNotificationChannel,
"testRecordMessages_invalidMsg");
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
- assertTrue(mBinderService.hasSentMessage(PKG, mUid));
+ assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
}
@Test
public void testRecordMessages_validMsg() throws RemoteException {
- // Messaging notification with shortcut info
- Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder("id").build();
Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
null /* groupKey */, false /* isSummary */);
- nb.setShortcutId("id");
- nb.setBubbleMetadata(metadata);
+ nb.setShortcutId(null);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- // Pretend the shortcut exists
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(PKG);
- when(info.getId()).thenReturn("id");
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
-
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
- assertFalse(mBinderService.hasSentMessage(PKG, mUid));
+ assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
+
+ nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
+ "testRecordMessages_validMsg");
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ assertFalse(mBinderService.isInInvalidMsgState(PKG, mUid));
+ }
+
+ @Test
+ public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException {
+ NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
+ "testRecordMessages_invalidMsg_afterValidMsg_1");
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation());
+
+ mBinderService.cancelAllNotifications(PKG, mUid);
+ waitForIdle();
+
+ Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
+ null /* groupKey */, false /* isSummary */);
+ nb.setShortcutId(null);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
+ new UserHandle(mUid), null, 0);
+ nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 9f593ce..6df3c7b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -39,7 +39,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.Notification;
@@ -90,7 +89,7 @@
@Mock private PackageManager mPm;
@Mock private ContentResolver mContentResolver;
- private final String pkg = PKG_N_MR1;
+ private final String mPkg = PKG_O;
private final int uid = 9583;
private final int id1 = 1;
private final String tag1 = "tag1";
@@ -198,10 +197,14 @@
}
Notification n = builder.build();
- return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
+ return new StatusBarNotification(mPkg, mPkg, id1, tag1, uid, uid, n, mUser, null, uid);
}
private StatusBarNotification getMessagingStyleNotification() {
+ return getMessagingStyleNotification(mPkg);
+ }
+
+ private StatusBarNotification getMessagingStyleNotification(String pkg) {
final Builder builder = new Builder(mMockContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon);
@@ -658,7 +661,7 @@
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+ record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
record.applyAdjustments();
@@ -687,7 +690,7 @@
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+ record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
record.applyAdjustments();
assertEquals(USER_SENTIMENT_POSITIVE, record.getUserSentiment());
@@ -705,7 +708,7 @@
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+ record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
record.applyAdjustments();
@@ -1134,6 +1137,35 @@
}
@Test
+ public void testIsConversation_noShortcut_appHasPreviousSentFullConversation() {
+ StatusBarNotification sbn = getMessagingStyleNotification();
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ record.setShortcutInfo(null);
+ record.setHasSentValidMsg(true);
+
+ assertFalse(record.isConversation());
+ }
+
+ @Test
+ public void testIsConversation_noShortcut_userDemotedApp() {
+ StatusBarNotification sbn = getMessagingStyleNotification();
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ record.setShortcutInfo(null);
+ record.userDemotedAppFromConvoSpace(true);
+
+ assertFalse(record.isConversation());
+ }
+
+ @Test
+ public void testIsConversation_noShortcut_targetsR() {
+ StatusBarNotification sbn = getMessagingStyleNotification(PKG_R);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ record.setShortcutInfo(null);
+
+ assertFalse(record.isConversation());
+ }
+
+ @Test
public void testIsConversation_channelDemoted() {
StatusBarNotification sbn = getMessagingStyleNotification();
channel.setDemoted(true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 4320f1c3..f4e5d56 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -454,7 +454,9 @@
mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
- mHelper.setMessageSent(PKG_P, UID_P);
+ mHelper.setInvalidMessageSent(PKG_P, UID_P);
+ mHelper.setValidMessageSent(PKG_P, UID_P);
+ mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
@@ -470,8 +472,10 @@
assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_O, UID_O));
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
- assertTrue(mHelper.hasSentMessage(PKG_P, UID_P));
- assertFalse(mHelper.hasSentMessage(PKG_N_MR1, UID_N_MR1));
+ assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P));
+ assertFalse(mHelper.hasSentInvalidMsg(PKG_N_MR1, UID_N_MR1));
+ assertTrue(mHelper.hasSentValidMsg(PKG_P, UID_P));
+ assertTrue(mHelper.didUserEverDemoteInvalidMsgApp(PKG_P, UID_P));
assertEquals(channel1,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
compareChannels(channel2,
@@ -3380,15 +3384,49 @@
}
@Test
- public void testMessageSent() {
+ public void testInvalidMessageSent() {
// create package preferences
mHelper.canShowBadge(PKG_P, UID_P);
// check default value
- assertFalse(mHelper.hasSentMessage(PKG_P, UID_P));
+ assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P));
// change it
- mHelper.setMessageSent(PKG_P, UID_P);
- assertTrue(mHelper.hasSentMessage(PKG_P, UID_P));
+ mHelper.setInvalidMessageSent(PKG_P, UID_P);
+ assertTrue(mHelper.isInInvalidMsgState(PKG_P, UID_P));
+ assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P));
+ }
+
+ @Test
+ public void testValidMessageSent() {
+ // create package preferences
+ mHelper.canShowBadge(PKG_P, UID_P);
+
+ // get into the bad state
+ mHelper.setInvalidMessageSent(PKG_P, UID_P);
+
+ // and then fix it
+ mHelper.setValidMessageSent(PKG_P, UID_P);
+
+ assertTrue(mHelper.hasSentValidMsg(PKG_P, UID_P));
+ assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P));
+ }
+
+ @Test
+ public void testUserDemotedInvalidMsgApp() {
+ // create package preferences
+ mHelper.canShowBadge(PKG_P, UID_P);
+
+ // demotion means nothing before msg notif sent
+ mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
+ assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
+
+ // it's valid when incomplete msgs have been sent
+ mHelper.setInvalidMessageSent(PKG_P, UID_P);
+ assertTrue(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
+
+ // and is invalid once complete msgs are sent
+ mHelper.setValidMessageSent(PKG_P, UID_P);
+ assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
}
}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index fdc9401..f382fba 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -58,6 +58,8 @@
android:screenOrientation="sensorLandscape"
android:showWhenLocked="true"
android:turnScreenOn="true" />
+ <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ResumeWhilePausingActivity"
+ android:resumeWhilePausing="true"/>
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
android:showWhenLocked="true" android:allowEmbedded="true"/>
</application>
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 8cfe96f..4da5adf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -35,6 +35,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -69,6 +70,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -82,14 +84,18 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
+import android.view.IWindowSession;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import androidx.test.filters.MediumTest;
@@ -488,6 +494,16 @@
}
@Test
+ public void testShouldMakeActive_nonTopVisible() {
+ ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ finishingActivity.finishing = true;
+ ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
+
+ assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
+ }
+
+ @Test
public void testShouldResume_stackVisibility() {
mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
spyOn(mStack);
@@ -1394,6 +1410,10 @@
assertTrue(displayRotation.isRotatingSeamlessly());
+ // The launching rotated app should not be cleared when waiting for remote rotation.
+ display.continueUpdateOrientationForDiffOrienLaunchingApp();
+ assertNotNull(display.mFixedRotationLaunchingApp);
+
// Simulate the rotation has been updated to previous one, e.g. sensor updates before the
// remote rotation is completed.
doReturn(originalRotation).when(displayRotation).rotationForOrientation(
@@ -1426,6 +1446,73 @@
}
@Test
+ public void testIsSnapshotCompatible() {
+ mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
+ final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+ .setRotation(mActivity.getWindowConfiguration().getRotation())
+ .build();
+
+ assertTrue(mActivity.isSnapshotCompatible(snapshot));
+
+ setRotatedScreenOrientationSilently(mActivity);
+
+ assertFalse(mActivity.isSnapshotCompatible(snapshot));
+ }
+
+ @Test
+ public void testFixedRotationSnapshotStartingWindow() {
+ mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
+ // TaskSnapshotSurface requires a fullscreen opaque window.
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+ params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
+ final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
+ mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+ mActivity.addWindow(w);
+
+ // Assume the activity is launching in different rotation, and there was an available
+ // snapshot accepted by {@link Activity#isSnapshotCompatible}.
+ final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+ .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
+ .build();
+ setRotatedScreenOrientationSilently(mActivity);
+
+ final IWindowSession session = WindowManagerGlobal.getWindowSession();
+ spyOn(session);
+ try {
+ // Return error to skip unnecessary operation.
+ doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
+ any() /* window */, anyInt() /* seq */, any() /* attrs */,
+ anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
+ any() /* outContentInsets */, any() /* outStableInsets */,
+ any() /* outDisplayCutout */, any() /* outInputChannel */,
+ any() /* outInsetsState */, any() /* outActiveControls */);
+ TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
+ } catch (RemoteException ignored) {
+ } finally {
+ reset(session);
+ }
+
+ // Because the rotation of snapshot and the corresponding top activity are different, fixed
+ // rotation should be applied when creating snapshot surface if the display rotation may be
+ // changed according to the activity orientation.
+ assertTrue(mActivity.hasFixedRotationTransform());
+ assertEquals(mActivity, mActivity.mDisplayContent.mFixedRotationLaunchingApp);
+ }
+
+ /**
+ * Sets orientation without notifying the parent to simulate that the display has not applied
+ * the requested orientation yet.
+ */
+ private static void setRotatedScreenOrientationSilently(ActivityRecord r) {
+ final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
+ doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
+ r.setOrientation(rotatedOrentation);
+ }
+
+ @Test
public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
final ActivityRecord secondaryDisplayActivity =
createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
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 822cb5a..64e08c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -76,6 +76,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
/**
* Tests for the {@link ActivityStack} class.
*
@@ -1327,6 +1330,8 @@
@Test
public void testCheckBehindFullscreenActivity() {
+ final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
+ final Consumer<ActivityRecord> handleBehindFullscreenActivity = occludedActivities::add;
final ActivityRecord bottomActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
final ActivityRecord topActivity =
@@ -1337,12 +1342,21 @@
assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
null /* handleBehindFullscreenActivity */));
+ // Top activity occludes bottom activity.
+ mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
+ assertThat(occludedActivities).containsExactly(bottomActivity);
+
doReturn(false).when(topActivity).occludesParent();
assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
null /* handleBehindFullscreenActivity */));
assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
null /* handleBehindFullscreenActivity */));
+ occludedActivities.clear();
+ // Top activity doesn't occlude parent, so the bottom activity is not occluded.
+ mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
+ assertThat(occludedActivities).isEmpty();
+
final ActivityRecord finishingActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
finishingActivity.finishing = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index fc256b0..702d9d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -53,6 +53,7 @@
import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageManagerService;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -161,6 +162,12 @@
mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
}
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ }
+
@Test
public void testSuspendedByAdminPackage() {
// GIVEN the package we're about to launch is currently suspended
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index edc9756..02d1f9b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -49,6 +49,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -56,10 +57,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -99,7 +100,6 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class ActivityStarterTests extends ActivityTestsBase {
- private ActivityStarter mStarter;
private ActivityStartController mController;
private ActivityMetricsLogger mActivityMetricsLogger;
private PackageManagerInternal mMockPackageManager;
@@ -127,8 +127,6 @@
mController = mock(ActivityStartController.class);
mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
clearInvocations(mActivityMetricsLogger);
- mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
- mock(ActivityStartInterceptor.class));
}
@Test
@@ -181,6 +179,7 @@
* {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
* the expected. It is important to note that the method also checks side effects of the start,
* such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
+ *
* @param preconditions A bitmask representing the preconditions for the launch
* @param launchFlags The launch flags to be provided by the launch {@link Intent}.
* @param expectedResult The expected result from the launch.
@@ -202,7 +201,7 @@
final WindowProcessController wpc =
containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
- doReturn(wpc).when(service).getProcessController(anyObject());
+ doReturn(wpc).when(service).getProcessController(any());
final Intent intent = new Intent();
intent.setFlags(launchFlags);
@@ -1034,4 +1033,46 @@
verify(recentTasks, times(1)).add(any());
}
+
+ @Test
+ public void testStartActivityInner_allSplitScreenPrimaryActivitiesVisible() {
+ // Given
+ final ActivityStarter starter = prepareStarter(0, false);
+
+ starter.setReason("testAllSplitScreenPrimaryActivitiesAreResumed");
+
+ final ActivityRecord targetRecord = new ActivityBuilder(mService).build();
+ targetRecord.setFocusable(false);
+ targetRecord.setVisibility(false);
+ final ActivityRecord sourceRecord = new ActivityBuilder(mService).build();
+
+ final ActivityStack stack = spy(
+ mRootWindowContainer.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
+ /* onTop */true));
+
+ stack.addChild(targetRecord);
+
+ doReturn(stack).when(mRootWindowContainer)
+ .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
+
+ starter.mStartActivity = new ActivityBuilder(mService).build();
+
+ // When
+ starter.startActivityInner(
+ /* r */targetRecord,
+ /* sourceRecord */ sourceRecord,
+ /* voiceSession */null,
+ /* voiceInteractor */ null,
+ /* startFlags */ 0,
+ /* doResume */true,
+ /* options */null,
+ /* inTask */null,
+ /* restrictedBgActivity */false);
+
+ // Then
+ verify(stack).ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ verify(targetRecord).makeVisibleIfNeeded(null, true);
+ assertTrue(targetRecord.mVisibleRequested);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 466f1a9..1fefb0c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -230,6 +230,7 @@
}
ActivityRecord build() {
+ SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
try {
mService.deferWindowLayout();
return buildInner();
@@ -295,6 +296,7 @@
// fullscreen value is normally read from resources in ctor, so for testing we need
// to set it somewhere else since we can't mock resources.
doReturn(true).when(activity).occludesParent();
+ doReturn(true).when(activity).fillsParent();
mTask.addChild(activity);
// Make visible by default...
activity.setVisible(true);
@@ -393,6 +395,8 @@
}
Task build() {
+ SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
+
if (mStack == null && mCreateStack) {
TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea
: mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
@@ -500,6 +504,8 @@
}
ActivityStack build() {
+ SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock);
+
final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
final ActivityStack stack = mTaskDisplayArea.createStackUnchecked(
mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index cf3cfec..07050d9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -31,10 +31,12 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -50,6 +52,7 @@
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.IWindowManager;
@@ -59,6 +62,8 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -303,7 +308,7 @@
public void testCreateRemoveStartingWindow() {
mActivity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
assertHasStartingWindow(mActivity);
mActivity.removeStartingWindow();
@@ -312,20 +317,16 @@
}
@Test
- @FlakyTest(bugId = 130392471)
public void testAddRemoveRace() {
// There was once a race condition between adding and removing starting windows
+ final ActivityRecord appToken = mAppWindow.mActivityRecord;
for (int i = 0; i < 1000; i++) {
- final ActivityRecord appToken = createIsolatedTestActivityRecord();
-
appToken.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
appToken.removeStartingWindow();
waitUntilHandlersIdle();
assertNoStartingWindow(appToken);
-
- appToken.getParent().getParent().removeImmediately();
}
}
@@ -335,11 +336,11 @@
final ActivityRecord activity2 = createIsolatedTestActivityRecord();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false, false);
+ true, true, false, true, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -355,16 +356,40 @@
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
activity1.appToken.asBinder(), true, true, false,
- true, false, false);
+ true, false);
});
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
}
+ @Test
+ public void testTransferStartingWindowCanAnimate() {
+ final ActivityRecord activity1 = createIsolatedTestActivityRecord();
+ final ActivityRecord activity2 = createIsolatedTestActivityRecord();
+ activity1.addStartingWindow(mPackageName,
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+ false);
+ waitUntilHandlersIdle();
+ activity2.addStartingWindow(mPackageName,
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
+ true, true, false, true, false);
+ waitUntilHandlersIdle();
+ assertNoStartingWindow(activity1);
+ assertHasStartingWindow(activity2);
+
+ // Assert that bottom activity is allowed to do animation.
+ doReturn(true).when(activity2).okToAnimate();
+ doReturn(true).when(activity2).isAnimating();
+ final OnAnimationFinishedCallback onAnimationFinishedCallback =
+ mock(OnAnimationFinishedCallback.class);
+ assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false,
+ onAnimationFinishedCallback));
+ }
+
private ActivityRecord createIsolatedTestActivityRecord() {
final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(taskStack, 0 /* userId */);
@@ -389,7 +414,7 @@
// Add a starting window.
activityTop.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
// Make the top one invisible, and try transferring the starting window from the top to the
@@ -408,20 +433,35 @@
removeGlobalMinSizeRestriction();
final Rect stackBounds = new Rect(0, 0, 1000, 600);
final Rect taskBounds = new Rect(100, 400, 600, 800);
- mStack.setBounds(stackBounds);
- mTask.setBounds(taskBounds);
+ // Set the bounds and windowing mode to window configuration directly, otherwise the
+ // testing setups may be discarded by configuration resolving.
+ mStack.getWindowConfiguration().setBounds(stackBounds);
+ mTask.getWindowConfiguration().setBounds(taskBounds);
+ mActivity.getWindowConfiguration().setBounds(taskBounds);
// Check that anim bounds for freeform window match task bounds
- mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_NONE));
// STACK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by
// bounds animation layer.
- mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
+ // Even the activity is smaller than task and it is not aligned to the top-left corner of
+ // task, the animation bounds the same as task and position should be zero because in real
+ // case the letterbox will fill the remaining area in task.
+ final Rect halfBounds = new Rect(taskBounds);
+ halfBounds.scale(0.5f);
+ mActivity.getWindowConfiguration().setBounds(halfBounds);
+ final Point animationPosition = new Point();
+ mActivity.getAnimationPosition(animationPosition);
+
+ assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
+ assertEquals(new Point(0, 0), animationPosition);
+
// STACK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later.
- mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
assertEquals(mStack.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index 6a1f50d..f4b50dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.RemoteException;
@@ -91,5 +92,11 @@
mDisplayContent.setBounds(new Rect(0, 0, 1000, 1000));
verify(organizer).onDisplayAreaInfoChanged(any());
+
+ Configuration tmpConfiguration = new Configuration();
+ tmpConfiguration.setTo(mDisplayContent.getRequestedOverrideConfiguration());
+ mDisplayContent.onRequestedOverrideConfigurationChanged(tmpConfiguration);
+ // Ensure it was still only called once if the bounds didn't change
+ verify(organizer).onDisplayAreaInfoChanged(any());
}
}
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 ac95a81..7b23bfb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,6 +57,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -1059,6 +1060,8 @@
@Test
public void testApplyTopFixedRotationTransform() {
mWm.mIsFixedRotationTransformEnabled = true;
+ mDisplayContent.getDisplayPolicy().addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs);
+ mDisplayContent.getDisplayPolicy().addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
final Configuration config90 = new Configuration();
mDisplayContent.computeScreenConfiguration(config90, ROTATION_90);
@@ -1079,6 +1082,12 @@
ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
false /* forceUpdate */));
+ assertNotNull(mDisplayContent.mFixedRotationAnimationController);
+ assertTrue(mStatusBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
+ ANIMATION_TYPE_FIXED_TRANSFORM));
+ assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
+ ANIMATION_TYPE_FIXED_TRANSFORM));
+
final Rect outFrame = new Rect();
final Rect outInsets = new Rect();
final Rect outStableInsets = new Rect();
@@ -1131,6 +1140,9 @@
assertFalse(app.hasFixedRotationTransform());
assertFalse(app2.hasFixedRotationTransform());
assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation);
+
+ mDisplayContent.finishFixedRotationAnimation();
+ assertNull(mDisplayContent.mFixedRotationAnimationController);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 28ae36a..27c4e9b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -27,9 +27,7 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -38,13 +36,10 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -52,7 +47,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
-import static org.junit.Assume.assumeTrue;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.testng.Assert.expectThrows;
@@ -66,18 +60,15 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InsetsState;
-import android.view.ViewRootImpl;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.utils.WmDisplayCutout;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -118,12 +109,6 @@
updateDisplayFrames();
}
- @After
- public void tearDown() {
- PolicyControl.setFilters("");
- mWindow.getDisplayContent().mInputMethodTarget = null;
- }
-
public void setRotation(int rotation) {
mRotation = rotation;
updateDisplayFrames();
@@ -212,8 +197,6 @@
@Test
public void layoutWindowLw_fitStatusBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
addWindow(mWindow);
@@ -230,8 +213,6 @@
@Test
public void layoutWindowLw_fitNavigationBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
mWindow.mAttrs.setFitInsetsTypes(Type.navigationBars());
addWindow(mWindow);
@@ -248,8 +229,6 @@
@Test
public void layoutWindowLw_fitAllSides() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
mWindow.mAttrs.setFitInsetsSides(Side.all());
addWindow(mWindow);
@@ -266,8 +245,6 @@
@Test
public void layoutWindowLw_fitTopOnly() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
mWindow.mAttrs.setFitInsetsSides(Side.TOP);
addWindow(mWindow);
@@ -284,8 +261,6 @@
@Test
public void layoutWindowLw_fitInsetsIgnoringVisibility() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final InsetsState state =
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow);
state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
@@ -306,8 +281,6 @@
@Test
public void layoutWindowLw_fitInsetsNotIgnoringVisibility() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
final InsetsState state =
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow);
state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
@@ -328,7 +301,6 @@
@Test
public void layoutWindowLw_fitDisplayCutout() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
addDisplayCutout();
mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout());
@@ -346,82 +318,6 @@
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
- // TODO(b/118118435): remove after migration
- @Test
- public void layoutWindowLw_appDrawsBarsLegacy() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
- }
-
- // TODO(b/118118435): remove after migration
- @Test
- public void layoutWindowLw_appWontDrawBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
- }
-
- // TODO(b/118118435): remove after migration
- @Test
- public void layoutWindowLw_appWontDrawBars_forceStatusAndNav() throws Exception {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
- mWindow.mAttrs.privateFlags = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
- }
-
- // TODO(b/118118435): remove after migration (keyguard dialog is not special with the new logic)
- @Test
- public void layoutWindowLw_keyguardDialog_hideNav() {
- mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null /* attached */, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
- }
-
@Test
public void layoutWindowLw_withDisplayCutout() {
addDisplayCutout();
@@ -761,31 +657,6 @@
}
@Test
- public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_NONE);
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
- addWindow(mWindow);
-
- final int forwardedInsetBottom = 50;
- mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(),
- STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(),
- STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
- assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
- }
-
- @Test
public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -806,117 +677,6 @@
assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
}
- // TODO(b/118118435): remove after removing PolicyControl
- @FlakyTest(bugId = 129711077)
- @Test
- public void layoutWindowLw_withImmersive_SoftInputAdjustResize() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- synchronized (mWm.mGlobalLock) {
- mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
- mWindow.mAttrs.flags = 0;
- mWindow.mAttrs.systemUiVisibility =
- SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-
- addWindow(mWindow);
-
- mWindow.getDisplayContent().mInputMethodTarget = mWindow;
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
- mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- int bottomInset = mFrames.mDisplayHeight - INPUT_METHOD_WINDOW_TOP;
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
- }
- }
-
- // TODO(b/118118435): remove after removing PolicyControl
- @FlakyTest(bugId = 129711077)
- @Test
- public void layoutWindowLw_withImmersive_SoftInputAdjustNothing() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- synchronized (mWm.mGlobalLock) {
- mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
- mWindow.mAttrs.flags = 0;
- mWindow.mAttrs.systemUiVisibility =
- SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-
- addWindow(mWindow);
-
- mWindow.getDisplayContent().mInputMethodTarget = mWindow;
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
- mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), 0, 0);
- }
- }
-
- // TODO(b/118118435): remove after removing PolicyControl
- @FlakyTest(bugId = 129711077)
- @Test
- public void layoutWindowLw_withForceImmersive_fullscreen() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- synchronized (mWm.mGlobalLock) {
- mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
- mWindow.mAttrs.flags = 0;
- mWindow.mAttrs.systemUiVisibility = 0;
- PolicyControl.setFilters(PolicyControl.NAME_IMMERSIVE_FULL + "=*");
-
- addWindow(mWindow);
-
- mWindow.getDisplayContent().mInputMethodTarget = mWindow;
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
- mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- int bottomInset = mFrames.mDisplayHeight - INPUT_METHOD_WINDOW_TOP;
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
- }
- }
-
- // TODO(b/118118435): remove after removing PolicyControl
- @FlakyTest(bugId = 129711077)
- @Test
- public void layoutWindowLw_withForceImmersive_nonFullscreen() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- synchronized (mWm.mGlobalLock) {
- mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
- mWindow.mAttrs.flags = 0;
- mWindow.mAttrs.systemUiVisibility = 0;
- mWindow.mAttrs.width = DISPLAY_WIDTH / 2;
- mWindow.mAttrs.height = DISPLAY_HEIGHT / 2;
- PolicyControl.setFilters(PolicyControl.NAME_IMMERSIVE_FULL + "=*");
-
- addWindow(mWindow);
-
- mWindow.getDisplayContent().mInputMethodTarget = mWindow;
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
- mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- int bottomInset = mFrames.mDisplayHeight - INPUT_METHOD_WINDOW_TOP;
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, bottomInset);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
- }
- }
-
@Test
public void layoutHint_appWindow() {
mWindow.mAttrs.flags =
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index c2db0c0..a3f9b2e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.Surface.ROTATION_0;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -56,7 +58,10 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.InsetsSource;
import android.view.InsetsState;
+import android.view.WindowInsets.Side;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -352,4 +357,36 @@
insetsPolicy.updateBarControlTarget(mAppWindow);
assertNull(displayPolicy.mInputConsumer);
}
+
+ @Test
+ public void testImeMinimalSourceFrame() {
+ final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = 1000;
+ displayInfo.logicalHeight = 2000;
+ displayInfo.rotation = ROTATION_0;
+ mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
+ displayInfo, null /* displayCutout */);
+
+ displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
+ mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
+
+ mDisplayContent.setInputMethodWindowLocked(mImeWindow);
+ mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+ mImeWindow.getGivenContentInsetsLw().set(0, displayInfo.logicalHeight, 0, 0);
+ mImeWindow.getControllableInsetProvider().setServerVisible(true);
+
+ displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */);
+ displayPolicy.layoutWindowLw(mImeWindow, null, mDisplayContent.mDisplayFrames);
+
+ final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
+ final InsetsSource imeSource = state.peekSource(ITYPE_IME);
+ final InsetsSource navBarSource = state.peekSource(ITYPE_NAVIGATION_BAR);
+
+ assertNotNull(imeSource);
+ assertNotNull(navBarSource);
+ assertFalse(imeSource.getFrame().isEmpty());
+ assertFalse(navBarSource.getFrame().isEmpty());
+ assertTrue(imeSource.getFrame().contains(navBarSource.getFrame()));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index ca01676..1d6dd0b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -16,8 +16,10 @@
package com.android.server.wm;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,12 +46,16 @@
private InsetsSource mSource = new InsetsSource(ITYPE_STATUS_BAR);
private InsetsSourceProvider mProvider;
+ private InsetsSource mImeSource = new InsetsSource(ITYPE_IME);
+ private InsetsSourceProvider mImeProvider;
@Before
public void setUp() throws Exception {
mSource.setVisible(true);
mProvider = new InsetsSourceProvider(mSource,
mDisplayContent.getInsetsStateController(), mDisplayContent);
+ mImeProvider = new InsetsSourceProvider(mImeSource,
+ mDisplayContent.getInsetsStateController(), mDisplayContent);
}
@Test
@@ -99,6 +105,7 @@
public void testPostLayout_frameProvider() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.mHasSurface = true;
mProvider.setWindow(statusBar,
(displayFrames, windowState, rect) -> {
rect.set(10, 10, 20, 20);
@@ -166,6 +173,30 @@
}
@Test
+ public void testUpdateSourceFrameForIme() {
+ final WindowState inputMethod = createWindow(null, TYPE_INPUT_METHOD, "inputMethod");
+
+ inputMethod.getFrameLw().set(new Rect(0, 400, 500, 500));
+
+ mImeProvider.setWindow(inputMethod, null, null);
+ mImeProvider.setServerVisible(false);
+ mImeSource.setVisible(true);
+ mImeProvider.updateSourceFrame();
+ assertEquals(new Rect(0, 0, 0, 0), mImeSource.getFrame());
+ Insets insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
+ false /* ignoreVisibility */);
+ assertEquals(Insets.of(0, 0, 0, 0), insets);
+
+ mImeProvider.setServerVisible(true);
+ mImeSource.setVisible(true);
+ mImeProvider.updateSourceFrame();
+ assertEquals(inputMethod.getFrameLw(), mImeSource.getFrame());
+ insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
+ false /* ignoreVisibility */);
+ assertEquals(Insets.of(0, 0, 0, 100), insets);
+ }
+
+ @Test
public void testInsetsModified() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
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 9066468..209db62 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -159,7 +158,7 @@
hiddenActivity.setVisible(false);
mDefaultDisplay.getConfiguration().windowConfiguration.setRotation(
mDefaultDisplay.getRotation());
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+ initializeRecentsAnimationController(mController, homeActivity);
// Ensure that we are animating the target activity as well
assertTrue(mController.isAnimatingTask(homeActivity.getTask()));
@@ -182,7 +181,7 @@
mDefaultDisplay.getConfiguration().windowConfiguration.setRotation(
mDefaultDisplay.getRotation());
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+ initializeRecentsAnimationController(mController, homeActivity);
mController.startAnimation();
// Ensure that we are animating the app and wallpaper target
@@ -205,7 +204,7 @@
mDefaultDisplay.getConfiguration().windowConfiguration.setRotation(
mDefaultDisplay.getRotation());
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+ initializeRecentsAnimationController(mController, homeActivity);
mController.startAnimation();
// Cancel the animation and ensure the controller is still running
@@ -231,7 +230,7 @@
doReturn(true).when(mDefaultDisplay.mWallpaperController).isWallpaperVisible();
// Start and finish the animation
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+ initializeRecentsAnimationController(mController, homeActivity);
mController.startAnimation();
assertTrue(mController.isAnimatingTask(homeActivity.getTask()));
@@ -342,7 +341,7 @@
assertEquals(Configuration.ORIENTATION_LANDSCAPE,
mDefaultDisplay.getConfiguration().orientation);
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+ initializeRecentsAnimationController(mController, homeActivity);
assertEquals(homeActivity, mDefaultDisplay.mFixedRotationLaunchingApp);
@@ -358,6 +357,30 @@
}
@Test
+ public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
+ final ActivityRecord homeActivity = createHomeActivity();
+ homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ // Assume an activity is launching to different rotation.
+ mDefaultDisplay.setFixedRotationLaunchingApp(activity,
+ (mDefaultDisplay.getRotation() + 1) % 4);
+
+ assertTrue(activity.hasFixedRotationTransform());
+ assertEquals(activity, mDefaultDisplay.mFixedRotationLaunchingApp);
+
+ // Before the transition is done, the recents animation is triggered.
+ initializeRecentsAnimationController(mController, homeActivity);
+ assertFalse(homeActivity.hasFixedRotationTransform());
+
+ // Simulate giving up the swipe up gesture to keep the original activity as top.
+ mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+ // The rotation transform should be cleared after updating orientation with display.
+ assertFalse(activity.hasFixedRotationTransform());
+ assertNull(mDefaultDisplay.mFixedRotationLaunchingApp);
+ }
+
+ @Test
public void testWallpaperHasFixedRotationApplied() {
mWm.mIsFixedRotationTransformEnabled = true;
mWm.setRecentsAnimationController(mController);
@@ -394,7 +417,7 @@
doReturn(true).when(mDefaultDisplay.mWallpaperController).isWallpaperVisible();
// Start the recents animation
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
+ initializeRecentsAnimationController(mController, homeActivity);
mDefaultDisplay.mWallpaperController.adjustWallpaperWindows();
@@ -433,6 +456,11 @@
return homeActivity;
}
+ private static void initializeRecentsAnimationController(RecentsAnimationController controller,
+ ActivityRecord activity) {
+ controller.initialize(activity.getActivityType(), new SparseBooleanArray(), activity);
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index 851b052..d7eedd9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
@@ -265,4 +266,15 @@
public SurfaceControl.Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction setFixedTransformHint(SurfaceControl sc,
+ @Surface.Rotation int transformHint) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
+ return this;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 552c476..79ba175 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -33,6 +33,7 @@
import static org.mockito.ArgumentMatchers.eq;
import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceControl.Transaction;
@@ -52,6 +53,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.PrintWriter;
+
/**
* Test class for {@link SurfaceAnimatorTest}.
*
@@ -267,6 +270,27 @@
assertFalse(mDeferFinishAnimatable.mFinishedCallbackCalled);
}
+ @Test
+ public void testDeferFinishFromAdapter() {
+
+ DeferredFinishAdapter deferredFinishAdapter = new DeferredFinishAdapter();
+ // Start animation
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, deferredFinishAdapter,
+ true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
+ assertAnimating(mAnimatable);
+ deferredFinishAdapter.mFinishCallback.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
+ deferredFinishAdapter);
+
+ assertAnimating(mAnimatable);
+ assertFalse(mAnimatable.mFinishedCallbackCalled);
+ // Now end defer finishing.
+ deferredFinishAdapter.mEndDeferFinishCallback.run();
+ assertNotAnimating(mAnimatable);
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ verify(mTransaction).remove(eq(deferredFinishAdapter.mAnimationLeash));
+ }
+
private OnAnimationFinishedCallback startDeferFinishAnimatable(AnimationAdapter anim) {
mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, anim,
true /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
@@ -389,4 +413,51 @@
return true;
}
}
+
+ private static class DeferredFinishAdapter implements AnimationAdapter {
+
+ private Runnable mEndDeferFinishCallback;
+ private OnAnimationFinishedCallback mFinishCallback;
+ private SurfaceControl mAnimationLeash;
+
+ @Override
+ public boolean getShowWallpaper() {
+ return true;
+ }
+
+ @Override
+ public void startAnimation(SurfaceControl animationLeash, Transaction t, int type,
+ OnAnimationFinishedCallback finishCallback) {
+ mFinishCallback = finishCallback;
+ mAnimationLeash = animationLeash;
+ }
+
+ @Override
+ public void onAnimationCancelled(SurfaceControl animationLeash) {
+ }
+
+ @Override
+ public long getDurationHint() {
+ return 100;
+ }
+
+ @Override
+ public long getStatusBarTransitionsStartTime() {
+ return 100;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ }
+
+ @Override
+ public void dumpDebug(ProtoOutputStream proto) {
+ }
+
+ @Override
+ public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ mEndDeferFinishCallback = endDeferFinishCallback;
+ return true;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index bce1320..218261b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -100,7 +100,6 @@
static int sNextDisplayId = DEFAULT_DISPLAY + 100;
static int sNextTaskId = 100;
- private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false);
private static final int[] TEST_USER_PROFILE_IDS = {};
private Context mContext;
@@ -419,20 +418,20 @@
if (wm == null) {
return;
}
- synchronized (mCurrentMessagesProcessed) {
- // Add a message to the handler queue and make sure it is fully processed before we move
- // on. This makes sure all previous messages in the handler are fully processed vs. just
- // popping them from the message queue.
- mCurrentMessagesProcessed.set(false);
- wm.mAnimator.getChoreographer().postFrameCallback(time -> {
- synchronized (mCurrentMessagesProcessed) {
- mCurrentMessagesProcessed.set(true);
- mCurrentMessagesProcessed.notifyAll();
- }
- });
- while (!mCurrentMessagesProcessed.get()) {
+ // Add a message to the handler queue and make sure it is fully processed before we move on.
+ // This makes sure all previous messages in the handler are fully processed vs. just popping
+ // them from the message queue.
+ final AtomicBoolean currentMessagesProcessed = new AtomicBoolean(false);
+ wm.mAnimator.getChoreographer().postFrameCallback(time -> {
+ synchronized (currentMessagesProcessed) {
+ currentMessagesProcessed.set(true);
+ currentMessagesProcessed.notifyAll();
+ }
+ });
+ while (!currentMessagesProcessed.get()) {
+ synchronized (currentMessagesProcessed) {
try {
- mCurrentMessagesProcessed.wait();
+ currentMessagesProcessed.wait();
} catch (InterruptedException e) {
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 20d9aff..f985a14 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -192,10 +192,18 @@
final ActivityManager.TaskSnapshot.Builder builder =
new ActivityManager.TaskSnapshot.Builder();
- mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
- PixelFormat.UNKNOWN, builder);
+ boolean success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
+ mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
+ assertTrue(success);
// The pixel format should be selected automatically.
assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat());
+
+ // Snapshot should not be taken while the rotation of activity and task are different.
+ doReturn(true).when(mAppWindow.mActivityRecord).hasFixedRotationTransform();
+ success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
+ mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
+
+ assertFalse(success);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 88de34d..bdcae48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -24,6 +24,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -39,10 +40,15 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.view.Surface;
+import com.android.server.LocalServices;
+
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import java.io.File;
import java.util.function.Predicate;
@@ -70,11 +76,26 @@
mLowResScale = lowResScale;
}
+ @BeforeClass
+ public static void setUpOnce() {
+ final UserManagerInternal userManager = mock(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, userManager);
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ }
+
@Before
public void setUp() {
final UserManager um = UserManager.get(getInstrumentation().getTargetContext());
mTestUserId = um.getUserHandle();
+ final UserManagerInternal userManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+ when(userManagerInternal.isUserUnlocked(mTestUserId)).thenReturn(true);
+
mContextSpy = spy(new ContextWrapper(mWm.mContext));
mResourcesSpy = spy(mContextSpy.getResources());
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 4e92ea0..2c17bbe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -81,6 +81,7 @@
@Before
public void setUp() throws Exception {
mService = ActivityManager.getService();
+ sTaskStackChangedCalled = false;
}
@After
@@ -114,6 +115,28 @@
@Test
@Presubmit
+ public void testTaskStackChanged_resumeWhilePausing() throws Exception {
+ registerTaskStackChangedListener(new TaskStackListener() {
+ @Override
+ public void onTaskStackChanged() throws RemoteException {
+ synchronized (sLock) {
+ sTaskStackChangedCalled = true;
+ }
+ }
+ });
+
+ final Context context = getInstrumentation().getContext();
+ context.startActivity(new Intent(context, ResumeWhilePausingActivity.class).addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK));
+ UiDevice.getInstance(getInstrumentation()).waitForIdle();
+
+ synchronized (sLock) {
+ assertTrue(sTaskStackChangedCalled);
+ }
+ }
+
+ @Test
+ @Presubmit
public void testTaskDescriptionChanged() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -173,7 +196,6 @@
*/
@Test
@Presubmit
- @FlakyTest(bugId = 130388819)
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
@@ -617,5 +639,7 @@
// Activity that has {@link android.R.attr#resizeableActivity} attribute set to {@code true}
public static class ActivityInActivityView extends TestActivity {}
+ public static class ResumeWhilePausingActivity extends TestActivity {}
+
public static class LandscapeActivity extends TestActivity {}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 520ac19..373f363 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -271,6 +271,29 @@
assertEquals(WINDOWING_MODE_FULLSCREEN, token.getWindowingMode());
}
+ @Test
+ public void testFixedRotationRecentsAnimatingTask() {
+ final RecentsAnimationController recentsController = mock(RecentsAnimationController.class);
+ doReturn(true).when(recentsController).isWallpaperVisible(eq(mAppWindow));
+ mWm.setRecentsAnimationController(recentsController);
+
+ mAppWindow.mActivityRecord.applyFixedRotationTransform(mDisplayContent.getDisplayInfo(),
+ mDisplayContent.mDisplayFrames, mDisplayContent.getConfiguration());
+ mAppWindow.mActivityRecord.mVisibleRequested = true;
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+
+ assertEquals(mAppWindow, mDisplayContent.mWallpaperController.getWallpaperTarget());
+ // Wallpaper should link the transform of its target.
+ assertTrue(mAppWindow.mActivityRecord.hasFixedRotationTransform());
+
+ mAppWindow.mActivityRecord.finishFixedRotationTransform();
+ // Invisible requested activity should not share its rotation transform.
+ mAppWindow.mActivityRecord.mVisibleRequested = false;
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+
+ assertFalse(mAppWindow.mActivityRecord.hasFixedRotationTransform());
+ }
+
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
.setStack(dc.getDefaultTaskDisplayArea().getRootHomeTask())
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 2ea58a0..fdc5c7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -836,7 +836,7 @@
spyOn(record);
doReturn(true).when(record).checkEnterPictureInPictureState(any(), anyBoolean());
- record.getRootTask().setHasBeenVisible(true);
+ record.getTask().setHasBeenVisible(true);
return record;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 65fb2c0..0346329 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -22,7 +22,6 @@
import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.Surface.ROTATION_0;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -75,17 +74,13 @@
import android.view.DisplayCutout;
import android.view.InsetsSource;
import android.view.SurfaceControl;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.utils.WmDisplayCutout;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -103,21 +98,6 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowStateTests extends WindowTestsBase {
- private static int sPreviousNewInsetsMode;
-
- @BeforeClass
- public static void setUpOnce() {
- // TODO: Make use of SettingsSession when it becomes feasible for this.
- sPreviousNewInsetsMode = ViewRootImpl.sNewInsetsMode;
- // To let the insets provider control the insets visibility, the insets mode has to be
- // NEW_INSETS_MODE_FULL.
- ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL;
- }
-
- @AfterClass
- public static void tearDownOnce() {
- ViewRootImpl.sNewInsetsMode = sPreviousNewInsetsMode;
- }
@Before
public void setUp() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index fc95556..4999361 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -34,14 +34,11 @@
/** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
static Task createTaskInStack(WindowManagerService service, ActivityStack stack, int userId) {
- synchronized (service.mGlobalLock) {
- final Task task = new ActivityTestsBase.TaskBuilder(
- stack.mStackSupervisor)
- .setUserId(userId)
- .setStack(stack)
- .build();
- return task;
- }
+ final Task task = new ActivityTestsBase.TaskBuilder(stack.mStackSupervisor)
+ .setUserId(userId)
+ .setStack(stack)
+ .build();
+ return task;
}
/** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */
@@ -52,23 +49,18 @@
}
static ActivityRecord createTestActivityRecord(ActivityStack stack) {
- synchronized (stack.mAtmService.mGlobalLock) {
- final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(
- stack.mAtmService)
- .setStack(stack)
- .setCreateTask(true)
- .build();
- postCreateActivitySetup(activity, stack.getDisplayContent());
- return activity;
- }
+ final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+ .setStack(stack)
+ .setCreateTask(true)
+ .build();
+ postCreateActivitySetup(activity, stack.getDisplayContent());
+ return activity;
}
static ActivityRecord createTestActivityRecord(DisplayContent dc) {
- synchronized (dc.mWmService.mGlobalLock) {
- final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build();
- postCreateActivitySetup(activity, dc);
- return activity;
- }
+ final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build();
+ postCreateActivitySetup(activity, dc);
+ return activity;
}
private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
@@ -84,9 +76,9 @@
static TestWindowToken createTestWindowToken(int type, DisplayContent dc,
boolean persistOnEmpty) {
- synchronized (dc.mWmService.mGlobalLock) {
- return new TestWindowToken(type, dc, persistOnEmpty);
- }
+ SystemServicesTestRule.checkHoldsLock(dc.mWmService.mGlobalLock);
+
+ return new TestWindowToken(type, dc, persistOnEmpty);
}
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 0eaab52..a1e5b80 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -55,11 +55,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
-/**
- * Common base class for window manager unit test classes.
- *
- * Make sure any requests to WM hold the WM lock if needed b/73966377
- */
+/** Common base class for window manager unit test classes. */
class WindowTestsBase extends SystemServiceTestsBase {
private static final String TAG = WindowTestsBase.class.getSimpleName();
@@ -94,43 +90,40 @@
@Before
public void setUpBase() {
+ mWm = mSystemServicesTestRule.getWindowManagerService();
+ SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
+
+ mTransaction = mSystemServicesTestRule.mTransaction;
+ mMockSession = mock(Session.class);
+ final Context context = getInstrumentation().getTargetContext();
// If @Before throws an exception, the error isn't logged. This will make sure any failures
// in the set up are clear. This can be removed when b/37850063 is fixed.
try {
- mMockSession = mock(Session.class);
-
- final Context context = getInstrumentation().getTargetContext();
-
- mWm = mSystemServicesTestRule.getWindowManagerService();
- mTransaction = mSystemServicesTestRule.mTransaction;
-
beforeCreateDisplay();
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay(true /* supportIme */);
// Set-up some common windows.
- synchronized (mWm.mGlobalLock) {
- mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
- mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
- mDisplayContent.mInputMethodWindow = mImeWindow;
- mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
- "mImeDialogWindow");
- mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
- mNotificationShadeWindow = createCommonWindow(null, TYPE_NOTIFICATION_SHADE,
- "mNotificationShadeWindow");
- mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
- mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
- "mDockedDividerWindow");
- mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
- mChildAppWindowAbove = createCommonWindow(mAppWindow,
- TYPE_APPLICATION_ATTACHED_DIALOG,
- "mChildAppWindowAbove");
- mChildAppWindowBelow = createCommonWindow(mAppWindow,
- TYPE_APPLICATION_MEDIA_OVERLAY,
- "mChildAppWindowBelow");
- mDisplayContent.getDisplayPolicy().setForceShowSystemBars(false);
- }
+ mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
+ mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
+ mDisplayContent.mInputMethodWindow = mImeWindow;
+ mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
+ "mImeDialogWindow");
+ mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
+ mNotificationShadeWindow = createCommonWindow(null, TYPE_NOTIFICATION_SHADE,
+ "mNotificationShadeWindow");
+ mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
+ mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
+ "mDockedDividerWindow");
+ mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
+ mChildAppWindowAbove = createCommonWindow(mAppWindow,
+ TYPE_APPLICATION_ATTACHED_DIALOG,
+ "mChildAppWindowAbove");
+ mChildAppWindowBelow = createCommonWindow(mAppWindow,
+ TYPE_APPLICATION_MEDIA_OVERLAY,
+ "mChildAppWindowBelow");
+ mDisplayContent.getDisplayPolicy().setForceShowSystemBars(false);
// Adding a display will cause freezing the display. Make sure to wait until it's
// unfrozen to not run into race conditions with the tests.
@@ -146,23 +139,19 @@
}
private WindowState createCommonWindow(WindowState parent, int type, String name) {
- synchronized (mWm.mGlobalLock) {
- final WindowState win = createWindow(parent, type, name);
- // Prevent common windows from been IMe targets
- win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
- return win;
- }
+ final WindowState win = createWindow(parent, type, name);
+ // Prevent common windows from been IME targets.
+ win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+ return win;
}
private WindowToken createWindowToken(
DisplayContent dc, int windowingMode, int activityType, int type) {
- synchronized (mWm.mGlobalLock) {
- if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
- return WindowTestUtils.createTestWindowToken(type, dc);
- }
-
- return createActivityRecord(dc, windowingMode, activityType);
+ if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
+ return WindowTestUtils.createTestWindowToken(type, dc);
}
+
+ return createActivityRecord(dc, windowingMode, activityType);
}
ActivityRecord createActivityRecord(DisplayContent dc, int windowingMode, int activityType) {
@@ -176,78 +165,60 @@
}
WindowState createWindow(WindowState parent, int type, String name) {
- synchronized (mWm.mGlobalLock) {
- return (parent == null)
- ? createWindow(parent, type, mDisplayContent, name)
- : createWindow(parent, type, parent.mToken, name);
- }
+ return (parent == null)
+ ? createWindow(parent, type, mDisplayContent, name)
+ : createWindow(parent, type, parent.mToken, name);
}
WindowState createWindow(WindowState parent, int type, String name, int ownerId) {
- synchronized (mWm.mGlobalLock) {
- return (parent == null)
- ? createWindow(parent, type, mDisplayContent, name, ownerId)
- : createWindow(parent, type, parent.mToken, name, ownerId);
- }
+ return (parent == null)
+ ? createWindow(parent, type, mDisplayContent, name, ownerId)
+ : createWindow(parent, type, parent.mToken, name, ownerId);
}
WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
int type, DisplayContent dc, String name) {
- synchronized (mWm.mGlobalLock) {
- final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
- return createWindow(parent, type, token, name);
- }
+ final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
+ return createWindow(parent, type, token, name);
}
WindowState createAppWindow(Task task, int type, String name) {
- synchronized (mWm.mGlobalLock) {
- final ActivityRecord activity =
- WindowTestUtils.createTestActivityRecord(task.getDisplayContent());
- task.addChild(activity, 0);
- return createWindow(null, type, activity, name);
- }
+ final ActivityRecord activity =
+ WindowTestUtils.createTestActivityRecord(task.getDisplayContent());
+ task.addChild(activity, 0);
+ return createWindow(null, type, activity, name);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
- synchronized (mWm.mGlobalLock) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name, 0 /* ownerId */);
- }
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+ return createWindow(parent, type, token, name, 0 /* ownerId */);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
int ownerId) {
- synchronized (mWm.mGlobalLock) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name, ownerId);
- }
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+ return createWindow(parent, type, token, name, ownerId);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
boolean ownerCanAddInternalSystemWindow) {
- synchronized (mWm.mGlobalLock) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name, 0 /* ownerId */,
- ownerCanAddInternalSystemWindow);
- }
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+ return createWindow(parent, type, token, name, 0 /* ownerId */,
+ ownerCanAddInternalSystemWindow);
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
- synchronized (mWm.mGlobalLock) {
- return createWindow(parent, type, token, name, 0 /* ownerId */,
- false /* ownerCanAddInternalSystemWindow */);
- }
+ return createWindow(parent, type, token, name, 0 /* ownerId */,
+ false /* ownerCanAddInternalSystemWindow */);
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId) {
- synchronized (mWm.mGlobalLock) {
- return createWindow(parent, type, token, name, ownerId,
- false /* ownerCanAddInternalSystemWindow */);
- }
+ return createWindow(parent, type, token, name, ownerId,
+ false /* ownerCanAddInternalSystemWindow */);
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
@@ -261,19 +232,19 @@
String name, int ownerId, int userId, boolean ownerCanAddInternalSystemWindow,
WindowManagerService service, Session session, IWindow iWindow,
WindowState.PowerManagerWrapper powerManagerWrapper) {
- synchronized (service.mGlobalLock) {
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
- attrs.setTitle(name);
+ SystemServicesTestRule.checkHoldsLock(service.mGlobalLock);
- final WindowState w = new WindowState(service, session, iWindow, token, parent,
- OP_NONE, 0, attrs, VISIBLE, ownerId, userId,
- ownerCanAddInternalSystemWindow,
- powerManagerWrapper);
- // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
- // adding it to the token...
- token.addWindow(w);
- return w;
- }
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+ attrs.setTitle(name);
+
+ final WindowState w = new WindowState(service, session, iWindow, token, parent,
+ OP_NONE, 0, attrs, VISIBLE, ownerId, userId,
+ ownerCanAddInternalSystemWindow,
+ powerManagerWrapper);
+ // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
+ // adding it to the token...
+ token.addWindow(w);
+ return w;
}
static void makeWindowVisible(WindowState... windows) {
@@ -292,30 +263,24 @@
}
ActivityStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
- synchronized (mWm.mGlobalLock) {
- return new ActivityTestsBase.StackBuilder(
- dc.mWmService.mAtmService.mRootWindowContainer)
- .setDisplay(dc)
- .setWindowingMode(windowingMode)
- .setActivityType(activityType)
- .setCreateActivity(false)
- .setIntent(new Intent())
- .build();
- }
+ return new ActivityTestsBase.StackBuilder(dc.mWmService.mRoot)
+ .setDisplay(dc)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setCreateActivity(false)
+ .setIntent(new Intent())
+ .build();
}
- ActivityStack createTaskStackOnTaskDisplayArea(
- int windowingMode, int activityType, TaskDisplayArea tda) {
- synchronized (mWm.mGlobalLock) {
- return new ActivityTestsBase.StackBuilder(
- tda.mDisplayContent.mWmService.mAtmService.mRootWindowContainer)
- .setTaskDisplayArea(tda)
- .setWindowingMode(windowingMode)
- .setActivityType(activityType)
- .setCreateActivity(false)
- .setIntent(new Intent())
- .build();
- }
+ ActivityStack createTaskStackOnTaskDisplayArea(int windowingMode, int activityType,
+ TaskDisplayArea tda) {
+ return new ActivityTestsBase.StackBuilder(tda.mWmService.mRoot)
+ .setTaskDisplayArea(tda)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setCreateActivity(false)
+ .setIntent(new Intent())
+ .build();
}
/** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
@@ -365,9 +330,9 @@
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
WindowToken token) {
- synchronized (mWm.mGlobalLock) {
- return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
- }
+ SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
+
+ return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
}
/** Creates a {@link DisplayContent} as parts of simulate display info for test. */
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 5ee3b48..fd462c2 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -234,6 +234,10 @@
event.mTaskRootClass = getCachedStringRef(stringPool.get(
parser.readInt(IntervalStatsProto.Event.TASK_ROOT_CLASS_INDEX) - 1));
break;
+ case (int) IntervalStatsProto.Event.LOCUS_ID_INDEX:
+ event.mLocusId = getCachedStringRef(stringPool.get(
+ parser.readInt(IntervalStatsProto.Event.LOCUS_ID_INDEX) - 1));
+ break;
case ProtoInputStream.NO_MORE_FIELDS:
// Handle default values for certain events types
switch (event.mEventType) {
@@ -252,6 +256,11 @@
event.mNotificationChannelId = "";
}
break;
+ case LOCUS_ID_SET:
+ if (event.mLocusId == null) {
+ event.mLocusId = "";
+ }
+ break;
}
return event;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
index 4468871..3163820 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
@@ -27,6 +27,8 @@
import com.android.server.LocalServices;
+import java.util.concurrent.TimeUnit;
+
/**
* JobService used to do any work for UsageStats while the device is idle.
*/
@@ -36,6 +38,11 @@
* Base job ID for the pruning job - must be unique within the system server uid.
*/
private static final int PRUNE_JOB_ID = 546357475;
+ /**
+ * Job ID for the update mappings job - must be unique within the system server uid.
+ * Incrementing PRUNE_JOB_ID by 21475 (MAX_USER_ID) to ensure there is no overlap in job ids.
+ */
+ private static final int UPDATE_MAPPINGS_JOB_ID = 546378950;
private static final String USER_ID_KEY = "user_id";
@@ -51,35 +58,65 @@
.setPersisted(true)
.build();
+ scheduleJobInternal(context, pruneJob, userJobId);
+ }
+
+ static void scheduleUpdateMappingsJob(Context context) {
+ final ComponentName component = new ComponentName(context.getPackageName(),
+ UsageStatsIdleService.class.getName());
+ final JobInfo updateMappingsJob = new JobInfo.Builder(UPDATE_MAPPINGS_JOB_ID, component)
+ .setPersisted(true)
+ .setMinimumLatency(TimeUnit.DAYS.toMillis(1))
+ .setOverrideDeadline(TimeUnit.DAYS.toMillis(2))
+ .build();
+
+ scheduleJobInternal(context, updateMappingsJob, UPDATE_MAPPINGS_JOB_ID);
+ }
+
+ private static void scheduleJobInternal(Context context, JobInfo pruneJob, int jobId) {
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
- final JobInfo pendingPruneJob = jobScheduler.getPendingJob(userJobId);
+ final JobInfo pendingPruneJob = jobScheduler.getPendingJob(jobId);
// only schedule a new prune job if one doesn't exist already for this user
if (!pruneJob.equals(pendingPruneJob)) {
- jobScheduler.cancel(userJobId); // cancel any previously scheduled prune job
+ jobScheduler.cancel(jobId); // cancel any previously scheduled prune job
jobScheduler.schedule(pruneJob);
}
-
}
static void cancelJob(Context context, int userId) {
- final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+ cancelJobInternal(context, PRUNE_JOB_ID + userId);
+ }
+
+ static void cancelUpdateMappingsJob(Context context) {
+ cancelJobInternal(context, UPDATE_MAPPINGS_JOB_ID);
+ }
+
+ private static void cancelJobInternal(Context context, int jobId) {
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
- jobScheduler.cancel(userJobId);
+ if (jobScheduler != null) {
+ jobScheduler.cancel(jobId);
+ }
}
@Override
public boolean onStartJob(JobParameters params) {
final PersistableBundle bundle = params.getExtras();
final int userId = bundle.getInt(USER_ID_KEY, -1);
- if (userId == -1) {
+ if (userId == -1 && params.getJobId() != UPDATE_MAPPINGS_JOB_ID) {
return false;
}
AsyncTask.execute(() -> {
final UsageStatsManagerInternal usageStatsManagerInternal = LocalServices.getService(
UsageStatsManagerInternal.class);
- final boolean pruned = usageStatsManagerInternal.pruneUninstalledPackagesData(userId);
- jobFinished(params, !pruned); // reschedule if data was not pruned
+ if (params.getJobId() == UPDATE_MAPPINGS_JOB_ID) {
+ final boolean jobFinished = usageStatsManagerInternal.updatePackageMappingsData();
+ jobFinished(params, !jobFinished); // reschedule if data was not updated
+ } else {
+ final boolean jobFinished =
+ usageStatsManagerInternal.pruneUninstalledPackagesData(userId);
+ jobFinished(params, !jobFinished); // reschedule if data was not pruned
+ }
});
return true;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 463fc37..78b1477 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -481,6 +481,13 @@
}
}
break;
+ case UsageEvents.Event.LOCUS_ID_SET:
+ if (event.mLocusId != null) {
+ final int locusIdIndex = stats.mStringCache.indexOf(event.mLocusId);
+ if (locusIdIndex >= 0) {
+ proto.write(IntervalStatsProto.Event.LOCUS_ID_INDEX, locusIdIndex + 1);
+ }
+ }
}
proto.end(token);
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 5b5d57bf..060ed51 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -88,6 +88,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -332,6 +333,11 @@
private void onUserUnlocked(int userId) {
// fetch the installed packages outside the lock so it doesn't block package manager.
final HashMap<String, Long> installedPackages = getInstalledPackages(userId);
+ // delay updating of package mappings for user 0 since their data is not likely to be stale.
+ // this also makes it less likely for restored data to be erased on unexpected reboots.
+ if (userId == UserHandle.USER_SYSTEM) {
+ UsageStatsIdleService.scheduleUpdateMappingsJob(getContext());
+ }
synchronized (mLock) {
// Create a user unlocked event to report
final Event unlockEvent = new Event(USER_UNLOCKED, SystemClock.elapsedRealtime());
@@ -543,8 +549,8 @@
* Initializes the given user's usage stats service - this should ideally only be called once,
* when the user is initially unlocked.
*/
- private void initializeUserUsageStatsServiceLocked(int userId,
- long currentTimeMillis, HashMap<String, Long> installedPackages) {
+ private void initializeUserUsageStatsServiceLocked(int userId, long currentTimeMillis,
+ HashMap<String, Long> installedPackages) {
final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
"usagestats");
final UserUsageStatsService service = new UserUsageStatsService(getContext(), userId,
@@ -810,6 +816,13 @@
} catch (IllegalArgumentException iae) {
Slog.e(TAG, "Failed to note usage start", iae);
}
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
+ mPackageManagerInternal.getPackageUid(event.mPackage, 0, userId),
+ event.mPackage,
+ event.mClass,
+ FrameworkStatsLog
+ .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_FOREGROUND);
break;
case Event.ACTIVITY_PAUSED:
if (event.mTaskRootPackage == null) {
@@ -824,6 +837,13 @@
event.mTaskRootClass = prevData.mTaskRootClass;
}
}
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
+ mPackageManagerInternal.getPackageUid(event.mPackage, 0, userId),
+ event.mPackage,
+ event.mClass,
+ FrameworkStatsLog
+ .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND);
break;
case Event.ACTIVITY_DESTROYED:
// Treat activity destroys like activity stops.
@@ -931,6 +951,7 @@
}
// Cancel any scheduled jobs for this user since the user is being removed.
UsageStatsIdleService.cancelJob(getContext(), userId);
+ UsageStatsIdleService.cancelUpdateMappingsJob(getContext());
}
/**
@@ -980,6 +1001,26 @@
/**
* Called by the Binder stub.
*/
+ private boolean updatePackageMappingsData() {
+ // fetch the installed packages outside the lock so it doesn't block package manager.
+ final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM);
+ synchronized (mLock) {
+ if (!mUserUnlockedStates.get(UserHandle.USER_SYSTEM)) {
+ return false; // user is no longer unlocked
+ }
+
+ final UserUsageStatsService userService = mUserState.get(UserHandle.USER_SYSTEM);
+ if (userService == null) {
+ return false; // user was stopped or removed
+ }
+
+ return userService.updatePackageMappingsLocked(installedPkgs);
+ }
+ }
+
+ /**
+ * Called by the Binder stub.
+ */
List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime,
boolean obfuscateInstantApps) {
synchronized (mLock) {
@@ -1847,7 +1888,7 @@
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
if (!hasPermissions(callingPackage,
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
- && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) {
+ && (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
+ "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions");
}
@@ -1874,7 +1915,7 @@
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
if (!hasPermissions(callingPackage,
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
- && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) {
+ && (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
+ "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions");
}
@@ -2137,6 +2178,9 @@
}
// Check to ensure that only user 0's data is b/r for now
+ // Note: if backup and restore is enabled for users other than the system user, the
+ // #onUserUnlocked logic, specifically when the update mappings job is scheduled via
+ // UsageStatsIdleService.scheduleUpdateMappingsJob, will have to be updated.
if (user == UserHandle.USER_SYSTEM) {
final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
if (userStats == null) {
@@ -2229,6 +2273,11 @@
public boolean pruneUninstalledPackagesData(int userId) {
return UsageStatsService.this.pruneUninstalledPackagesData(userId);
}
+
+ @Override
+ public boolean updatePackageMappingsData() {
+ return UsageStatsService.this.updatePackageMappingsData();
+ }
}
private class MyPackageMonitor extends PackageMonitor {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b7779fd..26de11a 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -40,6 +40,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -181,19 +182,27 @@
private void readPackageMappingsLocked(HashMap<String, Long> installedPackages) {
mDatabase.readMappingsLocked();
- updatePackageMappingsLocked(installedPackages);
+ // Package mappings for the system user are updated after 24 hours via a job scheduled by
+ // UsageStatsIdleService to ensure restored data is not lost on first boot. Additionally,
+ // this makes user service initialization a little quicker on subsequent boots.
+ if (mUserId != UserHandle.USER_SYSTEM) {
+ updatePackageMappingsLocked(installedPackages);
+ }
}
/**
- * Queries Job Scheduler for any pending data prune jobs and if any exist, it updates the
- * package mappings in memory by removing those tokens.
+ * Compares the package mappings on disk with the ones currently installed and removes the
+ * mappings for those packages that have been uninstalled.
* This will only happen once per device boot, when the user is unlocked for the first time.
+ * If the user is the system user (user 0), this is delayed to ensure data for packages
+ * that were restored isn't removed before the restore is complete.
*
* @param installedPackages map of installed packages (package_name:package_install_time)
+ * @return {@code true} on a successful mappings update, {@code false} otherwise.
*/
- private void updatePackageMappingsLocked(HashMap<String, Long> installedPackages) {
+ boolean updatePackageMappingsLocked(HashMap<String, Long> installedPackages) {
if (ArrayUtils.isEmpty(installedPackages)) {
- return;
+ return true;
}
final long timeNow = System.currentTimeMillis();
@@ -206,7 +215,7 @@
}
}
if (removedPackages.isEmpty()) {
- return;
+ return true;
}
// remove packages in the mappings that are no longer installed and persist to disk
@@ -217,7 +226,9 @@
mDatabase.writeMappingsLocked();
} catch (Exception e) {
Slog.w(TAG, "Unable to write updated package mappings file on service initialization.");
+ return false;
}
+ return true;
}
boolean pruneUninstalledPackagesData() {
@@ -1166,6 +1177,7 @@
byte[] getBackupPayload(String key){
checkAndGetTimeLocked();
+ persistActiveStats();
return mDatabase.getBackupPayload(key);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 42e2bbf..6c13cd7 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -346,12 +346,15 @@
sEventLogger.log(new SoundTriggerLogger.StringEvent("deleteSoundModel(): id = "
+ soundModelId));
- // Unload the model if it is loaded.
- mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
- mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
+ if (isInitialized()) {
+ // Unload the model if it is loaded.
+ mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
- // Stop recognition if it is started.
- mSoundModelStatTracker.onStop(soundModelId.getUuid());
+ // Stop tracking recognition if it is started.
+ mSoundModelStatTracker.onStop(soundModelId.getUuid());
+ }
+
+ mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
}
@Override
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index ead90bb..3365ab7 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -22,6 +22,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -1635,13 +1636,21 @@
/**
* Instructs Telecom to put the call into the background audio processing state.
- *
+ * <p>
* This method can be called either when the call is in {@link #STATE_RINGING} or
* {@link #STATE_ACTIVE}. After Telecom acknowledges the request by setting the call's state to
* {@link #STATE_AUDIO_PROCESSING}, your app may setup the audio paths with the audio stack in
* order to capture and play audio on the call stream.
- *
+ * <p>
* This method can only be called by the default dialer app.
+ * <p>
+ * Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which are using
+ * the microphone as part of audio processing should specify the foreground service type using
+ * the attribute {@link android.R.attr#foregroundServiceType} in the {@link InCallService}
+ * service element of the app's manifest file.
+ * The {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} attribute should be specified.
+ * @see <a href="https://developer.android.com/preview/privacy/foreground-service-types">
+ * the Android Developer Site</a> for more information.
* @hide
*/
@SystemApi
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index f8722f4..8abab90 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -23,6 +23,7 @@
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -281,9 +282,20 @@
* Sets whether to request background audio processing so that the in-call service can
* screen the call further. If set to {@code true}, {@link #setDisallowCall} should be
* called with {@code false}, and all other parameters in this builder will be ignored.
- *
+ * <p>
* This request will only be honored if the {@link CallScreeningService} shares the same
* uid as the default dialer app. Otherwise, the call will go through as usual.
+ * <p>
+ * Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which
+ * are using the microphone as part of audio processing should specify the
+ * foreground service type using the attribute
+ * {@link android.R.attr#foregroundServiceType} in the {@link CallScreeningService}
+ * service element of the app's manifest file.
+ * The {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} attribute should be
+ * specified.
+ * @see
+ * <a href="https://developer.android.com/preview/privacy/foreground-service-types">
+ * the Android Developer Site</a> for more information.
*
* @param shouldScreenCallViaAudioProcessing Whether to request further call screening.
* @hide
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index a716b37..56cba1d 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2102,12 +2102,12 @@
private void abort(String callId) {
- Log.d(this, "abort %s", callId);
+ Log.i(this, "abort %s", callId);
findConnectionForAction(callId, "abort").onAbort();
}
private void answerVideo(String callId, int videoState) {
- Log.d(this, "answerVideo %s", callId);
+ Log.i(this, "answerVideo %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "answer").onAnswer(videoState);
} else {
@@ -2116,7 +2116,7 @@
}
private void answer(String callId) {
- Log.d(this, "answer %s", callId);
+ Log.i(this, "answer %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "answer").onAnswer();
} else {
@@ -2125,12 +2125,12 @@
}
private void deflect(String callId, Uri address) {
- Log.d(this, "deflect %s", callId);
+ Log.i(this, "deflect %s", callId);
findConnectionForAction(callId, "deflect").onDeflect(address);
}
private void reject(String callId) {
- Log.d(this, "reject %s", callId);
+ Log.i(this, "reject %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "reject").onReject();
} else {
@@ -2139,34 +2139,34 @@
}
private void reject(String callId, String rejectWithMessage) {
- Log.d(this, "reject %s with message", callId);
+ Log.i(this, "reject %s with message", callId);
findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
}
private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
- Log.d(this, "reject %s with reason %d", callId, rejectReason);
+ Log.i(this, "reject %s with reason %d", callId, rejectReason);
findConnectionForAction(callId, "reject").onReject(rejectReason);
}
private void transfer(String callId, Uri number, boolean isConfirmationRequired) {
- Log.d(this, "transfer %s", callId);
+ Log.i(this, "transfer %s", callId);
findConnectionForAction(callId, "transfer").onTransfer(number, isConfirmationRequired);
}
private void consultativeTransfer(String callId, String otherCallId) {
- Log.d(this, "consultativeTransfer %s", callId);
+ Log.i(this, "consultativeTransfer %s", callId);
Connection connection1 = findConnectionForAction(callId, "consultativeTransfer");
Connection connection2 = findConnectionForAction(otherCallId, " consultativeTransfer");
connection1.onTransfer(connection2);
}
private void silence(String callId) {
- Log.d(this, "silence %s", callId);
+ Log.i(this, "silence %s", callId);
findConnectionForAction(callId, "silence").onSilence();
}
private void disconnect(String callId) {
- Log.d(this, "disconnect %s", callId);
+ Log.i(this, "disconnect %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "disconnect").onDisconnect();
} else {
@@ -2175,7 +2175,7 @@
}
private void hold(String callId) {
- Log.d(this, "hold %s", callId);
+ Log.i(this, "hold %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "hold").onHold();
} else {
@@ -2184,7 +2184,7 @@
}
private void unhold(String callId) {
- Log.d(this, "unhold %s", callId);
+ Log.i(this, "unhold %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "unhold").onUnhold();
} else {
@@ -2193,7 +2193,7 @@
}
private void onCallAudioStateChanged(String callId, CallAudioState callAudioState) {
- Log.d(this, "onAudioStateChanged %s %s", callId, callAudioState);
+ Log.i(this, "onAudioStateChanged %s %s", callId, callAudioState);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "onCallAudioStateChanged").setCallAudioState(
callAudioState);
@@ -2204,7 +2204,7 @@
}
private void playDtmfTone(String callId, char digit) {
- Log.d(this, "playDtmfTone %s %c", callId, digit);
+ Log.i(this, "playDtmfTone %s %c", callId, digit);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
} else {
@@ -2213,7 +2213,7 @@
}
private void stopDtmfTone(String callId) {
- Log.d(this, "stopDtmfTone %s", callId);
+ Log.i(this, "stopDtmfTone %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopDtmfTone").onStopDtmfTone();
} else {
@@ -2222,7 +2222,7 @@
}
private void conference(String callId1, String callId2) {
- Log.d(this, "conference %s, %s", callId1, callId2);
+ Log.i(this, "conference %s, %s", callId1, callId2);
// Attempt to get second connection or conference.
Connection connection2 = findConnectionForAction(callId2, "conference");
@@ -2269,7 +2269,7 @@
}
private void splitFromConference(String callId) {
- Log.d(this, "splitFromConference(%s)", callId);
+ Log.i(this, "splitFromConference(%s)", callId);
Connection connection = findConnectionForAction(callId, "splitFromConference");
if (connection == getNullConnection()) {
@@ -2284,7 +2284,7 @@
}
private void mergeConference(String callId) {
- Log.d(this, "mergeConference(%s)", callId);
+ Log.i(this, "mergeConference(%s)", callId);
Conference conference = findConferenceForAction(callId, "mergeConference");
if (conference != null) {
conference.onMerge();
@@ -2292,7 +2292,7 @@
}
private void swapConference(String callId) {
- Log.d(this, "swapConference(%s)", callId);
+ Log.i(this, "swapConference(%s)", callId);
Conference conference = findConferenceForAction(callId, "swapConference");
if (conference != null) {
conference.onSwap();
@@ -2300,7 +2300,7 @@
}
private void addConferenceParticipants(String callId, List<Uri> participants) {
- Log.d(this, "addConferenceParticipants(%s)", callId);
+ Log.i(this, "addConferenceParticipants(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "addConferenceParticipants")
.onAddConferenceParticipants(participants);
@@ -2318,7 +2318,7 @@
* @param callId The ID of the call to pull.
*/
private void pullExternalCall(String callId) {
- Log.d(this, "pullExternalCall(%s)", callId);
+ Log.i(this, "pullExternalCall(%s)", callId);
Connection connection = findConnectionForAction(callId, "pullExternalCall");
if (connection != null) {
connection.onPullExternalCall();
@@ -2335,7 +2335,7 @@
* @param extras Extras associated with the event.
*/
private void sendCallEvent(String callId, String event, Bundle extras) {
- Log.d(this, "sendCallEvent(%s, %s)", callId, event);
+ Log.i(this, "sendCallEvent(%s, %s)", callId, event);
Connection connection = findConnectionForAction(callId, "sendCallEvent");
if (connection != null) {
connection.onCallEvent(event, extras);
@@ -2348,7 +2348,7 @@
* @param callId The ID of the call which completed handover.
*/
private void notifyHandoverComplete(String callId) {
- Log.d(this, "notifyHandoverComplete(%s)", callId);
+ Log.i(this, "notifyHandoverComplete(%s)", callId);
Connection connection = findConnectionForAction(callId, "notifyHandoverComplete");
if (connection != null) {
connection.onHandoverComplete();
@@ -2368,7 +2368,7 @@
* @param extras The new extras bundle.
*/
private void handleExtrasChanged(String callId, Bundle extras) {
- Log.d(this, "handleExtrasChanged(%s, %s)", callId, extras);
+ Log.i(this, "handleExtrasChanged(%s, %s)", callId, extras);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
} else if (mConferenceById.containsKey(callId)) {
@@ -2377,7 +2377,7 @@
}
private void startRtt(String callId, Connection.RttTextStream rttTextStream) {
- Log.d(this, "startRtt(%s)", callId);
+ Log.i(this, "startRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "startRtt").onStartRtt(rttTextStream);
} else if (mConferenceById.containsKey(callId)) {
@@ -2386,7 +2386,7 @@
}
private void stopRtt(String callId) {
- Log.d(this, "stopRtt(%s)", callId);
+ Log.i(this, "stopRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopRtt").onStopRtt();
} else if (mConferenceById.containsKey(callId)) {
@@ -2395,7 +2395,7 @@
}
private void handleRttUpgradeResponse(String callId, Connection.RttTextStream rttTextStream) {
- Log.d(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null);
+ Log.i(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "handleRttUpgradeResponse")
.handleRttUpgradeResponse(rttTextStream);
@@ -2405,7 +2405,7 @@
}
private void onPostDialContinue(String callId, boolean proceed) {
- Log.d(this, "onPostDialContinue(%s)", callId);
+ Log.i(this, "onPostDialContinue(%s)", callId);
findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
}
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 4f6a9d6..a90d053 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,7 +16,9 @@
package android.telecom;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
@@ -29,8 +31,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.Locale;
+import java.util.stream.Collectors;
/**
* Manages logging for the entire module.
@@ -212,6 +216,16 @@
return getSessionManager().getExternalSession();
}
+ /**
+ * Retrieves external session information, providing a context for the recipient of the session
+ * info where the external session came from.
+ * @param ownerInfo The external owner info.
+ * @return New {@link Session.Info} instance with owner info set.
+ */
+ public static Session.Info getExternalSession(@NonNull String ownerInfo) {
+ return getSessionManager().getExternalSession(ownerInfo);
+ }
+
public static void cancelSubsession(Session subsession) {
getSessionManager().cancelSubsession(subsession);
}
@@ -481,4 +495,34 @@
}
return String.format(Locale.US, "%s: %s%s", prefix, msg, sessionPostfix);
}
+
+ /**
+ * Generates an abbreviated version of the package name from a component.
+ * E.g. com.android.phone becomes cap
+ * @param componentName The component name to abbreviate.
+ * @return Abbreviation of empty string if component is null.
+ * @hide
+ */
+ public static String getPackageAbbreviation(ComponentName componentName) {
+ if (componentName == null) {
+ return "";
+ }
+ return getPackageAbbreviation(componentName.getPackageName());
+ }
+
+ /**
+ * Generates an abbreviated version of the package name.
+ * E.g. com.android.phone becomes cap
+ * @param packageName The packageName name to abbreviate.
+ * @return Abbreviation of empty string if package is null.
+ * @hide
+ */
+ public static String getPackageAbbreviation(String packageName) {
+ if (packageName == null) {
+ return "";
+ }
+ return Arrays.stream(packageName.split("\\."))
+ .map(s -> s.substring(0,1))
+ .collect(Collectors.joining(""));
+ }
}
diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java
index 8d3f4e1..4aa3614 100644
--- a/telecomm/java/android/telecom/Logging/Session.java
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -17,6 +17,7 @@
package android.telecom.Logging;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.Log;
@@ -59,10 +60,12 @@
public static class Info implements Parcelable {
public final String sessionId;
public final String methodPath;
+ public final String ownerInfo;
- private Info(String id, String path) {
+ private Info(String id, String path, String owner) {
sessionId = id;
methodPath = path;
+ ownerInfo = owner;
}
public static Info getInfo (Session s) {
@@ -70,7 +73,28 @@
// not get multiple stacking external sessions (unless we have DEBUG level logging or
// lower).
return new Info(s.getFullSessionId(), s.getFullMethodPath(
- !Log.DEBUG && s.isSessionExternal()));
+ !Log.DEBUG && s.isSessionExternal()), s.getOwnerInfo());
+ }
+
+ public static Info getExternalInfo(Session s, @Nullable String ownerInfo) {
+ // When creating session information for an existing session, the caller may pass in a
+ // context to be passed along to the recipient of the external session info.
+ // So, for example, if telecom has an active session with owner 'cad', and Telecom is
+ // calling into Telephony and providing external session info, it would pass in 'cast'
+ // as the owner info. This would result in Telephony seeing owner info 'cad/cast',
+ // which would make it very clear in the Telephony logs the chain of package calls which
+ // ultimately resulted in the logs.
+ String newInfo = ownerInfo != null && s.getOwnerInfo() != null
+ // If we've got both, concatenate them.
+ ? s.getOwnerInfo() + "/" + ownerInfo
+ // Otherwise use whichever is present.
+ : ownerInfo != null ? ownerInfo : s.getOwnerInfo();
+
+ // Create Info based on the truncated method path if the session is external, so we do
+ // not get multiple stacking external sessions (unless we have DEBUG level logging or
+ // lower).
+ return new Info(s.getFullSessionId(), s.getFullMethodPath(
+ !Log.DEBUG && s.isSessionExternal()), newInfo);
}
/** Responsible for creating Info objects for deserialized Parcels. */
@@ -80,7 +104,8 @@
public Info createFromParcel(Parcel source) {
String id = source.readString();
String methodName = source.readString();
- return new Info(id, methodName);
+ String ownerInfo = source.readString();
+ return new Info(id, methodName, ownerInfo);
}
@Override
@@ -100,6 +125,7 @@
public void writeToParcel(Parcel destination, int flags) {
destination.writeString(sessionId);
destination.writeString(methodPath);
+ destination.writeString(ownerInfo);
}
}
@@ -206,6 +232,14 @@
return Info.getInfo(this);
}
+ public Info getExternalInfo(@Nullable String ownerInfo) {
+ return Info.getExternalInfo(this, ownerInfo);
+ }
+
+ public String getOwnerInfo() {
+ return mOwnerInfo;
+ }
+
@VisibleForTesting
public String getSessionId() {
return mSessionId;
diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java
index ac30058..67e5eab 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -16,6 +16,7 @@
package android.telecom.Logging;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -180,7 +181,7 @@
Log.d(LOGGING_TAG, Session.START_EXTERNAL_SESSION);
Session externalSession = new Session(Session.EXTERNAL_INDICATOR + sessionInfo.sessionId,
sessionInfo.methodPath, System.currentTimeMillis(),
- false /*isStartedFromActiveSession*/, null);
+ false /*isStartedFromActiveSession*/, sessionInfo.ownerInfo);
externalSession.setIsExternal(true);
// Mark the external session as already completed, since we have no way of knowing when
// the external session actually has completed.
@@ -224,7 +225,7 @@
// Start execution time of the session will be overwritten in continueSession(...).
Session newSubsession = new Session(threadSession.getNextChildId(),
threadSession.getShortMethodName(), System.currentTimeMillis(),
- isStartedFromActiveSession, null);
+ isStartedFromActiveSession, threadSession.getOwnerInfo());
threadSession.addChild(newSubsession);
newSubsession.setParentSession(threadSession);
@@ -238,12 +239,18 @@
return newSubsession;
}
+ public synchronized Session.Info getExternalSession() {
+ return getExternalSession(null /* ownerInfo */);
+ }
+
/**
* Retrieve the information of the currently active Session. This information is parcelable and
* is used to create an external Session ({@link #startExternalSession(Session.Info, String)}).
* If there is no Session active, this method will return null.
+ * @param ownerInfo Owner information for the session.
+ * @return The session information
*/
- public synchronized Session.Info getExternalSession() {
+ public synchronized Session.Info getExternalSession(@Nullable String ownerInfo) {
int threadId = getCallingThreadId();
Session threadSession = mSessionMapper.get(threadId);
if (threadSession == null) {
@@ -251,8 +258,7 @@
"active.");
return null;
}
-
- return threadSession.getInfo();
+ return threadSession.getExternalInfo(ownerInfo);
}
/**
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 05480dc..df336257 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -30,13 +30,16 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.telecom.Logging.Session;
import android.view.Surface;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
/**
* A connection provided to a {@link ConnectionService} by another {@code ConnectionService}
@@ -655,6 +658,7 @@
private int mCallerDisplayNamePresentation;
private RemoteConference mConference;
private Bundle mExtras;
+ private String mCallingPackageAbbreviation;
/**
* @hide
@@ -667,6 +671,13 @@
mConnectionService = connectionService;
mConnected = true;
mState = Connection.STATE_INITIALIZING;
+ if (request != null && request.getExtras() != null
+ && request.getExtras().containsKey(
+ Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME)) {
+ String callingPackage = request.getExtras().getString(
+ Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME);
+ mCallingPackageAbbreviation = Log.getPackageAbbreviation(callingPackage);
+ }
}
/**
@@ -705,6 +716,7 @@
Bundle newExtras = new Bundle();
newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
putExtras(newExtras);
+ mCallingPackageAbbreviation = Log.getPackageAbbreviation(callingPackage);
}
/**
@@ -899,11 +911,15 @@
* Instructs this {@code RemoteConnection} to abort.
*/
public void abort() {
+ Log.startSession("RC.a", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.abort(mConnectionId, null /*Session.Info*/);
+ mConnectionService.abort(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -911,11 +927,15 @@
* Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer.
*/
public void answer() {
+ Log.startSession("RC.an", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.answer(mConnectionId, null /*Session.Info*/);
+ mConnectionService.answer(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -925,11 +945,15 @@
* @hide
*/
public void answer(int videoState) {
+ Log.startSession("RC.an2", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.answerVideo(mConnectionId, videoState, null /*Session.Info*/);
+ mConnectionService.answerVideo(mConnectionId, videoState,
+ Log.getExternalSession(mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -937,11 +961,15 @@
* Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to reject.
*/
public void reject() {
+ Log.startSession("RC.r", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.reject(mConnectionId, null /*Session.Info*/);
+ mConnectionService.reject(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -949,11 +977,15 @@
* Instructs this {@code RemoteConnection} to go on hold.
*/
public void hold() {
+ Log.startSession("RC.h", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.hold(mConnectionId, null /*Session.Info*/);
+ mConnectionService.hold(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -961,11 +993,15 @@
* Instructs this {@link Connection#STATE_HOLDING} call to release from hold.
*/
public void unhold() {
+ Log.startSession("RC.u", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.unhold(mConnectionId, null /*Session.Info*/);
+ mConnectionService.unhold(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -973,11 +1009,15 @@
* Instructs this {@code RemoteConnection} to disconnect.
*/
public void disconnect() {
+ Log.startSession("RC.d", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.disconnect(mConnectionId, null /*Session.Info*/);
+ mConnectionService.disconnect(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -991,11 +1031,14 @@
* value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
*/
public void playDtmfTone(char digit) {
+ Log.startSession("RC.pDT", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.playDtmfTone(mConnectionId, digit, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1007,11 +1050,14 @@
* currently playing, this method will do nothing.
*/
public void stopDtmfTone() {
+ Log.startSession("RC.sDT", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.stopDtmfTone(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1037,12 +1083,16 @@
* @param proceed Whether or not to continue with the post-dial sequence.
*/
public void postDialContinue(boolean proceed) {
+ Log.startSession("RC.pDC", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.onPostDialContinue(mConnectionId, proceed,
null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ // bliss
+ } finally {
+ Log.endSession();
}
}
@@ -1052,11 +1102,14 @@
* See {@link Call#pullExternalCall()} for more information.
*/
public void pullExternalCall() {
+ Log.startSession("RC.pEC", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.pullExternalCall(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1079,12 +1132,15 @@
* @param state The audio state of this {@code RemoteConnection}.
*/
public void setCallAudioState(CallAudioState state) {
+ Log.startSession("RC.sCAS", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.onCallAudioStateChanged(mConnectionId, state,
null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1095,12 +1151,15 @@
* @hide
*/
public void startRtt(@NonNull Connection.RttTextStream rttTextStream) {
+ Log.startSession("RC.sR", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.startRtt(mConnectionId, rttTextStream.getFdFromInCall(),
rttTextStream.getFdToInCall(), null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1110,11 +1169,14 @@
* @hide
*/
public void stopRtt() {
+ Log.startSession("RC.stR", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.stopRtt(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1128,6 +1190,7 @@
* the in-call app.
*/
public void sendRttUpgradeResponse(@Nullable Connection.RttTextStream rttTextStream) {
+ Log.startSession("RC.sRUR", getActiveOwnerInfo());
try {
if (mConnected) {
if (rttTextStream == null) {
@@ -1140,6 +1203,8 @@
}
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1164,6 +1229,22 @@
return mConference;
}
+ /**
+ * Get the owner info for the currently active session. We want to make sure that any owner
+ * info from the original call into the connection manager gets retained so that the full
+ * context of the calls can be traced down to Telephony.
+ * Example: Telecom will provide owner info in it's external session info that indicates
+ * 'cast' as the calling owner.
+ * @return The active owner
+ */
+ private String getActiveOwnerInfo() {
+ Session.Info info = Log.getExternalSession();
+ if (info == null) {
+ return null;
+ }
+ return info.ownerInfo;
+ }
+
/** {@hide} */
String getId() {
return mConnectionId;
diff --git a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
new file mode 100644
index 0000000..6c63755
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Telephony;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * This class provides utility functions related to CellBroadcast.
+ */
+public class CellBroadcastUtils {
+ private static final String TAG = "CellBroadcastUtils";
+ private static final boolean VDBG = false;
+
+ /**
+ * Utility method to query the default CBR's package name.
+ */
+ public static String getDefaultCellBroadcastReceiverPackageName(Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ ResolveInfo resolveInfo = packageManager.resolveActivity(
+ new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION),
+ PackageManager.MATCH_SYSTEM_ONLY);
+ String packageName;
+
+ if (resolveInfo == null) {
+ Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: no package found");
+ return null;
+ }
+
+ packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+
+ if (VDBG) {
+ Log.d(TAG, "getDefaultCellBroadcastReceiverPackageName: found package: " + packageName);
+ }
+
+ if (TextUtils.isEmpty(packageName) || packageManager.checkPermission(
+ android.Manifest.permission.READ_CELL_BROADCASTS, packageName)
+ == PackageManager.PERMISSION_DENIED) {
+ Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: returning null; "
+ + "permission check failed for : " + packageName);
+ return null;
+ }
+
+ return packageName;
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 477bb1f..50ff8f4 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1632,6 +1632,12 @@
"show_precise_failed_cause_bool";
/**
+ * Boolean to decide whether NR is enabled.
+ * @hide
+ */
+ public static final String KEY_NR_ENABLED_BOOL = "nr_enabled_bool";
+
+ /**
* Boolean to decide whether LTE is enabled.
*/
public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
@@ -4139,6 +4145,7 @@
sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, "");
sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
+ sDefaults.putBoolean(KEY_NR_ENABLED_BOOL, true);
sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
@@ -4156,10 +4163,10 @@
});
sDefaults.putIntArray(KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY,
new int[] {
- -19, /* SIGNAL_STRENGTH_POOR */
+ -20, /* SIGNAL_STRENGTH_POOR */
-17, /* SIGNAL_STRENGTH_MODERATE */
-14, /* SIGNAL_STRENGTH_GOOD */
- -12 /* SIGNAL_STRENGTH_GREAT */
+ -11 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY,
new int[] {
@@ -4187,9 +4194,9 @@
// Boundaries: [-20 dB, -3 dB]
new int[] {
-16, /* SIGNAL_STRENGTH_POOR */
- -11, /* SIGNAL_STRENGTH_MODERATE */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
-9, /* SIGNAL_STRENGTH_GOOD */
- -7 /* SIGNAL_STRENGTH_GREAT */
+ -6 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
// Boundaries: [-23 dB, 40 dB]
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 8562df1..95fe90a 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -57,9 +57,9 @@
// Boundaries: [-20 dB, -3 dB]
private int[] mSsRsrqThresholds = new int[] {
-16, /* SIGNAL_STRENGTH_POOR */
- -11, /* SIGNAL_STRENGTH_MODERATE */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
-9, /* SIGNAL_STRENGTH_GOOD */
- -7 /* SIGNAL_STRENGTH_GREAT */
+ -6 /* SIGNAL_STRENGTH_GREAT */
};
// Lifted from Default carrier configs and max range of SSSINR
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 07d71d0..c6b06b4 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1392,15 +1392,16 @@
/** @hide */
public boolean isUsingCarrierAggregation() {
+ boolean isUsingCa = false;
NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (nri != null) {
DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
if (dsri != null) {
- return dsri.isUsingCarrierAggregation();
+ isUsingCa = dsri.isUsingCarrierAggregation();
}
}
- return false;
+ return isUsingCa || getCellBandwidths().length > 1;
}
/** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 3546434..d62cd0a 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -837,20 +837,20 @@
+ " carrierId=" + mCarrierId + " displayName=" + mDisplayName
+ " carrierName=" + mCarrierName + " nameSource=" + mNameSource
+ " iconTint=" + mIconTint
- + " mNumber=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber)
- + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
- + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
- + " nativeAccessRules " + Arrays.toString(mNativeAccessRules)
+ + " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber)
+ + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc=" + mMcc
+ + " mnc=" + mMnc + " countryIso=" + mCountryIso + " isEmbedded=" + mIsEmbedded
+ + " nativeAccessRules=" + Arrays.toString(mNativeAccessRules)
+ " cardString=" + cardStringToPrint + " cardId=" + mCardId
- + " isOpportunistic=" + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
- + " mIsGroupDisabled=" + mIsGroupDisabled
+ + " isOpportunistic=" + mIsOpportunistic + " groupUUID=" + mGroupUUID
+ + " isGroupDisabled=" + mIsGroupDisabled
+ " profileClass=" + mProfileClass
+ " ehplmns=" + Arrays.toString(mEhplmns)
+ " hplmns=" + Arrays.toString(mHplmns)
+ " subscriptionType=" + mSubscriptionType
- + " mGroupOwner=" + mGroupOwner
+ + " groupOwner=" + mGroupOwner
+ " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules)
- + " mAreUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + "}";
+ + " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + "}";
}
@Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 97a4f4e..4246aef 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10415,7 +10415,7 @@
* <p>To recognize a carrier (including MVNO) as a first-class identity, Android assigns each
* carrier with a canonical integer a.k.a. carrier id. The carrier ID is an Android
* platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
- * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
*
* <p>Apps which have carrier-specific configurations or business logic can use the carrier id
* as an Android platform-wide identifier for carriers.
@@ -10477,7 +10477,7 @@
*
* <p>For carriers without fine-grained specific carrier ids, return {@link #getSimCarrierId()}
* <p>Specific carrier ids are defined in the same way as carrier id
- * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
* except each with a "parent" id linking to its top-level carrier id.
*
* @return Returns fine-grained carrier id of the current subscription.
@@ -10526,7 +10526,7 @@
* This is used for fallback when configurations/logic for exact carrier id
* {@link #getSimCarrierId()} are not found.
*
- * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
* can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
* was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
* by default. After carrier id table update, a new carrier id was assigned. If apps don't
@@ -10553,7 +10553,7 @@
* used for fallback when configurations/logic for exact carrier id {@link #getSimCarrierId()}
* are not found.
*
- * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
* can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
* was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
* by default. After carrier id table update, a new carrier id was assigned. If apps don't
@@ -13098,7 +13098,9 @@
service.userActivity();
}
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ // one-way notification, if telephony is not available, it is okay to not throw
+ // exception here.
+ Log.w(TAG, "notifyUserActivity exception: " + e.getMessage());
}
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index ede67dd..94407f1 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -56,14 +56,15 @@
* Activity Action: Show the opt-in dialog for enabling or disabling RCS contact discovery
* using User Capability Exchange (UCE).
* <p>
- * An application that depends on contact discovery being enabled may send this intent
+ * An application that depends on RCS contact discovery being enabled must send this intent
* using {@link Context#startActivity(Intent)} to ask the user to opt-in for contacts upload for
- * capability exchange if it is currently disabled. Whether or not this setting has been enabled
- * can be queried using {@link RcsUceAdapter#isUceSettingEnabled()}.
+ * capability exchange if it is currently disabled. Whether or not RCS contact discovery has
+ * been enabled by the user can be queried using {@link RcsUceAdapter#isUceSettingEnabled()}.
* <p>
- * This intent should only be sent if the carrier supports RCS capability exchange, which can be
- * queried using the key {@link CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL}. Otherwise, the
- * setting will not be present.
+ * This intent will always be handled by the system, however the application should only send
+ * this Intent if the carrier supports RCS contact discovery, which can be queried using the key
+ * {@link CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL}. Otherwise, the RCS contact discovery
+ * opt-in dialog will not be shown.
* <p>
* Input: A mandatory {@link Settings#EXTRA_SUB_ID} extra containing the subscription that the
* setting will be be shown for.
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 05ab6bd..ec11279 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -363,9 +363,10 @@
/**
* Change the user’s setting for whether or not UCE is enabled for the associated subscription.
* <p>
- * If an application Requires UCE, they may launch an Activity using the Intent
+ * If an application Requires UCE, they will launch an Activity using the Intent
* {@link ImsRcsManager#ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN}, which will ask the user if
- * they wish to enable this feature.
+ * they wish to enable this feature. This setting should only be enabled after the user has
+ * opted-in to capability exchange.
* <p>
* Note: This setting does not affect whether or not the device publishes its service
* capabilities if the subscription supports presence publication.
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index ff70f8b..29286e8 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -240,5 +240,5 @@
* two.
* Type: int
*/
- static final String PROPERTY_MAX_ACTIVE_MODEMS = "ro.telephony.max.active.modems";
+ static final String PROPERTY_MAX_ACTIVE_MODEMS = "telephony.active_modems.max_count";
}
diff --git a/test-base/api/lint-baseline.txt b/test-base/api/lint-baseline.txt
new file mode 100644
index 0000000..86c8a91
--- /dev/null
+++ b/test-base/api/lint-baseline.txt
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+MissingNullability: junit.framework.ComparisonFailure#getMessage():
+ Missing nullability on method `getMessage` return
diff --git a/test-mock/api/lint-baseline.txt b/test-mock/api/lint-baseline.txt
new file mode 100644
index 0000000..1411824
--- /dev/null
+++ b/test-mock/api/lint-baseline.txt
@@ -0,0 +1,143 @@
+// Baseline format: 1.0
+ArrayReturn: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #1:
+ Method parameter should be Collection<ContentValues> (or subclass) instead of raw array; was `android.content.ContentValues[]`
+ArrayReturn: android.test.mock.MockResources#getTextArray(int):
+ Method should return Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]`
+
+
+MissingNullability: android.test.mock.MockApplication#onConfigurationChanged(android.content.res.Configuration) parameter #0:
+ Missing nullability on parameter `newConfig` in method `onConfigurationChanged`
+MissingNullability: android.test.mock.MockContentProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0:
+ Missing nullability on parameter `context` in method `attachInfo`
+MissingNullability: android.test.mock.MockContentProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1:
+ Missing nullability on parameter `info` in method `attachInfo`
+MissingNullability: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #0:
+ Missing nullability on parameter `uri` in method `bulkInsert`
+MissingNullability: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #1:
+ Missing nullability on parameter `values` in method `bulkInsert`
+MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String):
+ Missing nullability on method `getStreamTypes` return
+MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String) parameter #0:
+ Missing nullability on parameter `url` in method `getStreamTypes`
+MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String) parameter #1:
+ Missing nullability on parameter `mimeTypeFilter` in method `getStreamTypes`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `instanceName` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `executor` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #4:
+ Missing nullability on parameter `conn` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindService`
+MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `executor` in method `bindService`
+MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `conn` in method `bindService`
+MissingNullability: android.test.mock.MockContext#createWindowContext(int, android.os.Bundle) parameter #1:
+ Missing nullability on parameter `options` in method `createWindowContext`
+MissingNullability: android.test.mock.MockContext#getDisplay():
+ Missing nullability on method `getDisplay` return
+MissingNullability: android.test.mock.MockContext#getMainExecutor():
+ Missing nullability on method `getMainExecutor` return
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #0:
+ Missing nullability on parameter `intent` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #1:
+ Missing nullability on parameter `receiverPermission` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #2:
+ Missing nullability on parameter `receiverAppOp` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #3:
+ Missing nullability on parameter `resultReceiver` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #4:
+ Missing nullability on parameter `scheduler` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #6:
+ Missing nullability on parameter `initialData` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #7:
+ Missing nullability on parameter `initialExtras` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#updateServiceGroup(android.content.ServiceConnection, int, int) parameter #0:
+ Missing nullability on parameter `conn` in method `updateServiceGroup`
+MissingNullability: android.test.mock.MockCursor#getNotificationUris():
+ Missing nullability on method `getNotificationUris` return
+MissingNullability: android.test.mock.MockCursor#setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>) parameter #0:
+ Missing nullability on parameter `cr` in method `setNotificationUris`
+MissingNullability: android.test.mock.MockCursor#setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>) parameter #1:
+ Missing nullability on parameter `uris` in method `setNotificationUris`
+MissingNullability: android.test.mock.MockPackageManager#getPackageArchiveInfo(String, int):
+ Missing nullability on method `getPackageArchiveInfo` return
+MissingNullability: android.test.mock.MockPackageManager#getPackageArchiveInfo(String, int) parameter #0:
+ Missing nullability on parameter `archiveFilePath` in method `getPackageArchiveInfo`
+MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(String, byte[], int) parameter #0:
+ Missing nullability on parameter `packageName` in method `hasSigningCertificate`
+MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(String, byte[], int) parameter #1:
+ Missing nullability on parameter `certificate` in method `hasSigningCertificate`
+MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(int, byte[], int) parameter #1:
+ Missing nullability on parameter `certificate` in method `hasSigningCertificate`
+MissingNullability: android.test.mock.MockResources#getAnimation(int):
+ Missing nullability on method `getAnimation` return
+MissingNullability: android.test.mock.MockResources#getConfiguration():
+ Missing nullability on method `getConfiguration` return
+MissingNullability: android.test.mock.MockResources#getDisplayMetrics():
+ Missing nullability on method `getDisplayMetrics` return
+MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #0:
+ Missing nullability on parameter `name` in method `getIdentifier`
+MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #1:
+ Missing nullability on parameter `defType` in method `getIdentifier`
+MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #2:
+ Missing nullability on parameter `defPackage` in method `getIdentifier`
+MissingNullability: android.test.mock.MockResources#getIntArray(int):
+ Missing nullability on method `getIntArray` return
+MissingNullability: android.test.mock.MockResources#getLayout(int):
+ Missing nullability on method `getLayout` return
+MissingNullability: android.test.mock.MockResources#getQuantityString(int, int):
+ Missing nullability on method `getQuantityString` return
+MissingNullability: android.test.mock.MockResources#getQuantityString(int, int, java.lang.Object...):
+ Missing nullability on method `getQuantityString` return
+MissingNullability: android.test.mock.MockResources#getQuantityString(int, int, java.lang.Object...) parameter #2:
+ Missing nullability on parameter `formatArgs` in method `getQuantityString`
+MissingNullability: android.test.mock.MockResources#getQuantityText(int, int):
+ Missing nullability on method `getQuantityText` return
+MissingNullability: android.test.mock.MockResources#getResourceEntryName(int):
+ Missing nullability on method `getResourceEntryName` return
+MissingNullability: android.test.mock.MockResources#getResourceName(int):
+ Missing nullability on method `getResourceName` return
+MissingNullability: android.test.mock.MockResources#getResourcePackageName(int):
+ Missing nullability on method `getResourcePackageName` return
+MissingNullability: android.test.mock.MockResources#getResourceTypeName(int):
+ Missing nullability on method `getResourceTypeName` return
+MissingNullability: android.test.mock.MockResources#getString(int):
+ Missing nullability on method `getString` return
+MissingNullability: android.test.mock.MockResources#getString(int, java.lang.Object...):
+ Missing nullability on method `getString` return
+MissingNullability: android.test.mock.MockResources#getString(int, java.lang.Object...) parameter #1:
+ Missing nullability on parameter `formatArgs` in method `getString`
+MissingNullability: android.test.mock.MockResources#getStringArray(int):
+ Missing nullability on method `getStringArray` return
+MissingNullability: android.test.mock.MockResources#getText(int):
+ Missing nullability on method `getText` return
+MissingNullability: android.test.mock.MockResources#getText(int, CharSequence):
+ Missing nullability on method `getText` return
+MissingNullability: android.test.mock.MockResources#getText(int, CharSequence) parameter #1:
+ Missing nullability on parameter `def` in method `getText`
+MissingNullability: android.test.mock.MockResources#getTextArray(int):
+ Missing nullability on method `getTextArray` return
+MissingNullability: android.test.mock.MockResources#getValue(String, android.util.TypedValue, boolean) parameter #0:
+ Missing nullability on parameter `name` in method `getValue`
+MissingNullability: android.test.mock.MockResources#getValue(String, android.util.TypedValue, boolean) parameter #1:
+ Missing nullability on parameter `outValue` in method `getValue`
+MissingNullability: android.test.mock.MockResources#getValue(int, android.util.TypedValue, boolean) parameter #1:
+ Missing nullability on parameter `outValue` in method `getValue`
+MissingNullability: android.test.mock.MockResources#getXml(int):
+ Missing nullability on method `getXml` return
+MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]):
+ Missing nullability on method `obtainAttributes` return
+MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]) parameter #0:
+ Missing nullability on parameter `set` in method `obtainAttributes`
+MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]) parameter #1:
+ Missing nullability on parameter `attrs` in method `obtainAttributes`
+MissingNullability: android.test.mock.MockResources#obtainTypedArray(int):
+ Missing nullability on method `obtainTypedArray` return
+MissingNullability: android.test.mock.MockResources#openRawResource(int):
+ Missing nullability on method `openRawResource` return
+MissingNullability: android.test.mock.MockResources#openRawResourceFd(int):
+ Missing nullability on method `openRawResourceFd` return
diff --git a/test-mock/api/system-lint-baseline.txt b/test-mock/api/system-lint-baseline.txt
new file mode 100644
index 0000000..466bc53
--- /dev/null
+++ b/test-mock/api/system-lint-baseline.txt
@@ -0,0 +1,15 @@
+// Baseline format: 1.0
+IntentBuilderName: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler):
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiverForAllUsers`
+
+
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler):
+ Missing nullability on method `registerReceiverForAllUsers` return
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #0:
+ Missing nullability on parameter `receiver` in method `registerReceiverForAllUsers`
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #1:
+ Missing nullability on parameter `filter` in method `registerReceiverForAllUsers`
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #2:
+ Missing nullability on parameter `broadcastPermission` in method `registerReceiverForAllUsers`
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #3:
+ Missing nullability on parameter `scheduler` in method `registerReceiverForAllUsers`
diff --git a/test-runner/api/lint-baseline.txt b/test-runner/api/lint-baseline.txt
new file mode 100644
index 0000000..54947fe
--- /dev/null
+++ b/test-runner/api/lint-baseline.txt
@@ -0,0 +1,173 @@
+// Baseline format: 1.0
+GenericException: android.test.ActivityInstrumentationTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityInstrumentationTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityInstrumentationTestCase2#runTest():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.test.ActivityInstrumentationTestCase2#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityInstrumentationTestCase2#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityUnitTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityUnitTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ApplicationTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ApplicationTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase2#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase2#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ServiceTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ServiceTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.SingleLaunchActivityTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.SingleLaunchActivityTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.SyncBaseInstrumentation#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+
+
+IntentBuilderName: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter):
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiver`
+
+
+MissingNullability: android.test.ComparisonFailure#getMessage():
+ Missing nullability on method `getMessage` return
+MissingNullability: android.test.InstrumentationTestRunner#onCreate(android.os.Bundle) parameter #0:
+ Missing nullability on parameter `arguments` in method `onCreate`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `instanceName` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `executor` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #4:
+ Missing nullability on parameter `conn` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, android.content.ServiceConnection, int) parameter #0:
+ Missing nullability on parameter `service` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, android.content.ServiceConnection, int) parameter #1:
+ Missing nullability on parameter `conn` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `executor` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `conn` in method `bindService`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #0:
+ Missing nullability on parameter `uri` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #1:
+ Missing nullability on parameter `readPermission` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #2:
+ Missing nullability on parameter `writePermission` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, int, int, int) parameter #0:
+ Missing nullability on parameter `uri` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#getContentResolver():
+ Missing nullability on method `getContentResolver` return
+MissingNullability: android.test.IsolatedContext#getFilesDir():
+ Missing nullability on method `getFilesDir` return
+MissingNullability: android.test.IsolatedContext#getSystemService(String):
+ Missing nullability on method `getSystemService` return
+MissingNullability: android.test.IsolatedContext#getSystemService(String) parameter #0:
+ Missing nullability on parameter `name` in method `getSystemService`
+MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter):
+ Missing nullability on method `registerReceiver` return
+MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) parameter #0:
+ Missing nullability on parameter `receiver` in method `registerReceiver`
+MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) parameter #1:
+ Missing nullability on parameter `filter` in method `registerReceiver`
+MissingNullability: android.test.IsolatedContext#sendBroadcast(android.content.Intent) parameter #0:
+ Missing nullability on parameter `intent` in method `sendBroadcast`
+MissingNullability: android.test.IsolatedContext#sendOrderedBroadcast(android.content.Intent, String) parameter #0:
+ Missing nullability on parameter `intent` in method `sendOrderedBroadcast`
+MissingNullability: android.test.IsolatedContext#sendOrderedBroadcast(android.content.Intent, String) parameter #1:
+ Missing nullability on parameter `receiverPermission` in method `sendOrderedBroadcast`
+MissingNullability: android.test.IsolatedContext#unregisterReceiver(android.content.BroadcastReceiver) parameter #0:
+ Missing nullability on parameter `receiver` in method `unregisterReceiver`
+MissingNullability: android.test.RenamingDelegatingContext#databaseList():
+ Missing nullability on method `databaseList` return
+MissingNullability: android.test.RenamingDelegatingContext#deleteDatabase(String) parameter #0:
+ Missing nullability on parameter `name` in method `deleteDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#deleteFile(String) parameter #0:
+ Missing nullability on parameter `name` in method `deleteFile`
+MissingNullability: android.test.RenamingDelegatingContext#fileList():
+ Missing nullability on method `fileList` return
+MissingNullability: android.test.RenamingDelegatingContext#getCacheDir():
+ Missing nullability on method `getCacheDir` return
+MissingNullability: android.test.RenamingDelegatingContext#getDatabasePath(String):
+ Missing nullability on method `getDatabasePath` return
+MissingNullability: android.test.RenamingDelegatingContext#getDatabasePath(String) parameter #0:
+ Missing nullability on parameter `name` in method `getDatabasePath`
+MissingNullability: android.test.RenamingDelegatingContext#getFileStreamPath(String):
+ Missing nullability on method `getFileStreamPath` return
+MissingNullability: android.test.RenamingDelegatingContext#getFileStreamPath(String) parameter #0:
+ Missing nullability on parameter `name` in method `getFileStreamPath`
+MissingNullability: android.test.RenamingDelegatingContext#openFileInput(String):
+ Missing nullability on method `openFileInput` return
+MissingNullability: android.test.RenamingDelegatingContext#openFileInput(String) parameter #0:
+ Missing nullability on parameter `name` in method `openFileInput`
+MissingNullability: android.test.RenamingDelegatingContext#openFileOutput(String, int):
+ Missing nullability on method `openFileOutput` return
+MissingNullability: android.test.RenamingDelegatingContext#openFileOutput(String, int) parameter #0:
+ Missing nullability on parameter `name` in method `openFileOutput`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory):
+ Missing nullability on method `openOrCreateDatabase` return
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory) parameter #0:
+ Missing nullability on parameter `name` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory) parameter #2:
+ Missing nullability on parameter `factory` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler):
+ Missing nullability on method `openOrCreateDatabase` return
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #0:
+ Missing nullability on parameter `name` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #2:
+ Missing nullability on parameter `factory` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #3:
+ Missing nullability on parameter `errorHandler` in method `openOrCreateDatabase`
+
+
+ProtectedMember: android.test.ActivityInstrumentationTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase.setUp()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase.tearDown()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase2#runTest():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.runTest()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase2#setUp():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.setUp()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase2#tearDown():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.tearDown()}
+ProtectedMember: android.test.ActivityUnitTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ActivityUnitTestCase.setUp()}
+ProtectedMember: android.test.ActivityUnitTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ActivityUnitTestCase.tearDown()}
+ProtectedMember: android.test.ApplicationTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ApplicationTestCase.setUp()}
+ProtectedMember: android.test.ApplicationTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ApplicationTestCase.tearDown()}
+ProtectedMember: android.test.ProviderTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase.setUp()}
+ProtectedMember: android.test.ProviderTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase.tearDown()}
+ProtectedMember: android.test.ProviderTestCase2#setUp():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase2.setUp()}
+ProtectedMember: android.test.ProviderTestCase2#tearDown():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase2.tearDown()}
+ProtectedMember: android.test.ServiceTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ServiceTestCase.setUp()}
+ProtectedMember: android.test.ServiceTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ServiceTestCase.tearDown()}
+ProtectedMember: android.test.SingleLaunchActivityTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.SingleLaunchActivityTestCase.setUp()}
+ProtectedMember: android.test.SingleLaunchActivityTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.SingleLaunchActivityTestCase.tearDown()}
+ProtectedMember: android.test.SyncBaseInstrumentation#setUp():
+ Protected methods not allowed; must be public: method android.test.SyncBaseInstrumentation.setUp()}
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index f2f0be7..1122cd8 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -16,16 +16,23 @@
package android.test;
+import static android.view.WindowInsets.Type.displayCutout;
+import static android.view.WindowInsets.Type.navigationBars;
+
import android.app.Activity;
import android.app.Instrumentation;
-import android.graphics.Point;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.os.SystemClock;
-import android.view.Display;
+import android.util.Size;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
/**
* Reusable methods for generating touch events. These methods can be used with
@@ -59,13 +66,12 @@
* @param activity The activity that is in the foreground of the test case
*/
public static void dragQuarterScreenDown(InstrumentationTestCase test, Activity activity) {
- Display display = activity.getWindowManager().getDefaultDisplay();
- final Point size = new Point();
- display.getSize(size);
+ WindowManager wm = activity.getWindowManager();
+ final Size size = getSizeExcludingNavigationBarAndCutout(wm.getCurrentWindowMetrics());
- final float x = size.x / 2.0f;
- final float fromY = size.y * 0.5f;
- final float toY = size.y * 0.75f;
+ final float x = size.getWidth() / 2.0f;
+ final float fromY = size.getHeight() * 0.5f;
+ final float toY = size.getHeight() * 0.75f;
drag(test, x, x, fromY, toY, 4);
}
@@ -89,17 +95,27 @@
* @param activity The activity that is in the foreground of the test case
*/
public static void dragQuarterScreenUp(InstrumentationTestCase test, Activity activity) {
- Display display = activity.getWindowManager().getDefaultDisplay();
- final Point size = new Point();
- display.getSize(size);
+ WindowManager wm = activity.getWindowManager();
+ final Size size = getSizeExcludingNavigationBarAndCutout(wm.getCurrentWindowMetrics());
- final float x = size.x / 2.0f;
- final float fromY = size.y * 0.5f;
- final float toY = size.y * 0.25f;
+ final float x = size.getWidth() / 2.0f;
+ final float fromY = size.getHeight() * 0.5f;
+ final float toY = size.getHeight() * 0.25f;
drag(test, x, x, fromY, toY, 4);
}
+ private static Size getSizeExcludingNavigationBarAndCutout(WindowMetrics windowMetrics) {
+ WindowInsets windowInsets = windowMetrics.getWindowInsets();
+ final Insets insetsWithCutout = windowInsets
+ .getInsetsIgnoringVisibility(navigationBars() | displayCutout());
+ final int insetsWidth = insetsWithCutout.left + insetsWithCutout.right;
+ final int insetsHeight = insetsWithCutout.top + insetsWithCutout.bottom;
+
+ Rect bounds = windowMetrics.getBounds();
+ return new Size(bounds.width() - insetsWidth, bounds.height() - insetsHeight);
+ }
+
/**
* Scroll a ViewGroup to the bottom by repeatedly calling
* {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
@@ -222,8 +238,9 @@
*/
public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v,
int stepCount) {
- int screenHeight =
- activity.getWindowManager().getCurrentWindowMetrics().getBounds().height();
+ WindowManager wm = activity.getWindowManager();
+ final int screenHeight = getSizeExcludingNavigationBarAndCutout(
+ wm.getCurrentWindowMetrics()).getHeight();
int[] xy = new int[2];
v.getLocationOnScreen(xy);
diff --git a/tests/GamePerformance/src/android/gameperformance/CustomControlView.java b/tests/GamePerformance/src/android/gameperformance/CustomControlView.java
index e63736b..8d11a41 100644
--- a/tests/GamePerformance/src/android/gameperformance/CustomControlView.java
+++ b/tests/GamePerformance/src/android/gameperformance/CustomControlView.java
@@ -15,20 +15,21 @@
*/
package android.gameperformance;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.WorkerThread;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Point;
import android.graphics.drawable.AnimationDrawable;
+import android.view.WindowManager;
import android.widget.AbsoluteLayout;
import android.widget.ImageView;
+import android.window.WindowMetricsHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
/**
* View that holds requested number of UI controls as ImageView with an infinite animation.
@@ -42,9 +43,10 @@
public CustomControlView(@NonNull Context context) {
super(context);
- final Point size = new Point();
- context.getDisplay().getSize(size);
- mPerRowControlCount = size.x / CONTROL_DIMENSION;
+ final WindowManager wm = context.getSystemService(WindowManager.class);
+ final int width = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ wm.getCurrentWindowMetrics()).width();
+ mPerRowControlCount = width / CONTROL_DIMENSION;
}
/**
diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
index 31532a2..8afe841 100644
--- a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
+++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
@@ -39,6 +39,7 @@
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.window.WindowMetricsHelper;
public class MirrorSurfaceActivity extends Activity implements View.OnClickListener,
View.OnLongClickListener, View.OnTouchListener {
@@ -89,7 +90,8 @@
.getSystemService(WindowManager.class);
mIWm = WindowManagerGlobal.getWindowManagerService();
- Rect windowBounds = mWm.getCurrentWindowMetrics().getBounds();
+ Rect windowBounds = WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout(
+ mWm.getCurrentWindowMetrics());
mWindowBounds.set(0, 0, windowBounds.width(), windowBounds.height());
mScaleText = findViewById(R.id.scale);
diff --git a/tests/NullHomeTest/Android.bp b/tests/NullHomeTest/Android.bp
new file mode 100644
index 0000000..99248bf
--- /dev/null
+++ b/tests/NullHomeTest/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// 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: "NullHomeTest",
+ srcs: ["src/**/*.java"],
+ certificate: "platform",
+ platform_apis: true,
+ static_libs: ["android-support-test"],
+ test_suites: ["device-tests"],
+}
diff --git a/tests/NullHomeTest/AndroidManifest.xml b/tests/NullHomeTest/AndroidManifest.xml
new file mode 100644
index 0000000..dc6402e
--- /dev/null
+++ b/tests/NullHomeTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.nullhome"
+ android:sharedUserId="android.uid.system" >
+
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.nullhome"
+ android:label="Check if no null Home exists/is enabled" />
+
+ <application android:label="Null Home Test">
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
new file mode 100644
index 0000000..1d77cdc5
--- /dev/null
+++ b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
@@ -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.test.nullhome;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * Check if NullHome/SystemUserHome activity does not exist/is disabled.
+ *
+ * SystemUserHome is only enabled in bootable CSI (csi_x86, csi_arm64)
+ * products and should not be enabled in other products.
+ *
+ * Shell's NullHome is empty and caused issues in sevaral manual GUI tests
+ * that try to select/use it, and should be removed.
+ *
+ * Settings' FallbackHome is fine because it's specially handled by Settings.
+ *
+ */
+
+@RunWith(JUnit4.class)
+public class NullHomeTest {
+ private static final String TAG = "NullHomeTest";
+ private Context mContext;
+ private PackageManager mPm;
+
+ @Before
+ public void before() {
+ Log.d(TAG, "beforeClass()");
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mPm = mContext.getPackageManager();
+ }
+
+ @Test
+ public void checkNullHome() {
+ final List<ResolveInfo> homeActivities = new ArrayList<>();
+
+ mPm.getHomeActivities(homeActivities);
+ for (ResolveInfo activity : homeActivities) {
+ Log.d(TAG, "Home activity: " + activity.activityInfo.packageName);
+ Assert.assertNotEquals(activity.activityInfo.packageName,
+ "com.android.internal.app.SystemUserHomeActivity");
+ Assert.assertNotEquals(activity.activityInfo.packageName,
+ "com.android.shell");
+ }
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java b/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java
index 2bf6040..e21dec3 100644
--- a/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/ClippedListActivity.java
@@ -15,27 +15,24 @@
*/
package com.android.test.uibench;
-import android.os.Bundle;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import androidx.appcompat.app.ActionBarDrawerToggle;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.ListFragment;
+
+import com.android.test.uibench.listview.CompatListActivity;
import com.google.android.material.navigation.NavigationView;
-public class ClippedListActivity extends AppCompatActivity
+public class ClippedListActivity extends CompatListActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ protected void initializeActivity() {
setContentView(R.layout.activity_navigation_drawer);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
@@ -48,15 +45,17 @@
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
+ }
- FragmentManager fm = getSupportFragmentManager();
- if (fm.findFragmentById(android.R.id.content) == null) {
- ListFragment listFragment = new ListFragment();
- ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
- TextUtils.buildSimpleStringList(40));
- listFragment.setListAdapter(adapter);
- fm.beginTransaction().add(R.id.app_bar_layout, listFragment).commit();
- }
+ @Override
+ protected ListAdapter createListAdapter() {
+ return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+ TextUtils.buildSimpleStringList(40));
+ }
+
+ @Override
+ protected int getListFragmentContainerViewId() {
+ return R.id.app_bar_layout;
}
@Override
diff --git a/tests/UiBench/src/com/android/test/uibench/MainActivity.java b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
index 0a7aa42..77a6c32 100644
--- a/tests/UiBench/src/com/android/test/uibench/MainActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
@@ -19,13 +19,15 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.ListFragment;
-import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
+import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
+import androidx.fragment.app.ListFragment;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
@@ -34,10 +36,12 @@
import java.util.List;
import java.util.Map;
-public class MainActivity extends AppCompatActivity {
+public class MainActivity extends CompatListActivity {
private static final String EXTRA_PATH = "activity_path";
private static final String CATEGORY_HWUI_TEST = "com.android.test.uibench.TEST";
+ private String mActivityPath = "";
+
public static class TestListFragment extends ListFragment {
@Override
@SuppressWarnings("unchecked")
@@ -56,9 +60,7 @@
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
+ protected void initializeActivity() {
Intent intent = getIntent();
String path = intent.getStringExtra(EXTRA_PATH);
@@ -68,15 +70,19 @@
// not root level, display where we are in the hierarchy
setTitle(path);
}
+ mActivityPath = path;
+ }
- FragmentManager fm = getSupportFragmentManager();
- if (fm.findFragmentById(android.R.id.content) == null) {
- ListFragment listFragment = new TestListFragment();
- listFragment.setListAdapter(new SimpleAdapter(this, getData(path),
- android.R.layout.simple_list_item_1, new String[] { "title" },
- new int[] { android.R.id.text1 }));
- fm.beginTransaction().add(android.R.id.content, listFragment).commit();
- }
+ @Override
+ protected ListAdapter createListAdapter() {
+ return new SimpleAdapter(this, getData(mActivityPath),
+ android.R.layout.simple_list_item_1, new String[] { "title" },
+ new int[] { android.R.id.text1 });
+ }
+
+ @Override
+ protected ListFragment createListFragment() {
+ return new TestListFragment();
}
protected List<Map<String, Object>> getData(String prefix) {
diff --git a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
index af7c65a..d6e1d06 100644
--- a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
@@ -16,13 +16,15 @@
package com.android.test.uibench;
import android.os.Bundle;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.ListFragment;
-import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
-public class ShadowGridActivity extends AppCompatActivity {
+import androidx.fragment.app.ListFragment;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
+public class ShadowGridActivity extends CompatListActivity {
public static class NoDividerListFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
@@ -31,18 +33,14 @@
}
};
+ @Override
+ protected ListAdapter createListAdapter() {
+ return new ArrayAdapter<>(this, R.layout.card_row, R.id.card_text,
+ TextUtils.buildSimpleStringList());
+ }
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- FragmentManager fm = getSupportFragmentManager();
- if (fm.findFragmentById(android.R.id.content) == null) {
- ListFragment listFragment = new NoDividerListFragment();
-
- listFragment.setListAdapter(new ArrayAdapter<>(this,
- R.layout.card_row, R.id.card_text, TextUtils.buildSimpleStringList()));
- fm.beginTransaction().add(android.R.id.content, listFragment).commit();
- }
+ protected ListFragment createListFragment() {
+ return new NoDividerListFragment();
}
}
diff --git a/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
index 6659558..9a4b527 100644
--- a/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
@@ -16,22 +16,29 @@
package com.android.test.uibench.listview;
import android.os.Bundle;
+import android.widget.ListAdapter;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.ListFragment;
-import androidx.appcompat.app.AppCompatActivity;
-import android.widget.ListAdapter;
public abstract class CompatListActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ initializeActivity();
+ int containerViewId = getListFragmentContainerViewId();
FragmentManager fm = getSupportFragmentManager();
- if (fm.findFragmentById(android.R.id.content) == null) {
+ Fragment fragment = fm.findFragmentById(containerViewId);
+ if (fragment == null) {
ListFragment listFragment = createListFragment();
listFragment.setListAdapter(createListAdapter());
- fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+ fm.beginTransaction().add(containerViewId, listFragment).commit();
+ } else if (fragment instanceof ListFragment) {
+ ((ListFragment) fragment).setListAdapter(createListAdapter());
}
}
@@ -40,4 +47,11 @@
protected ListFragment createListFragment() {
return new ListFragment();
}
+
+ protected int getListFragmentContainerViewId() {
+ return android.R.id.content;
+ }
+
+ protected void initializeActivity() {
+ }
}
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
index bd313ad..2f0d6ab 100644
--- a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
@@ -17,16 +17,17 @@
import android.content.Context;
import android.os.Bundle;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.test.uibench.R;
public abstract class RvCompatListActivity extends AppCompatActivity {
@@ -51,14 +52,21 @@
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
- if (fm.findFragmentById(android.R.id.content) == null) {
+ Fragment existingFragment = fm.findFragmentById(android.R.id.content);
+ if (existingFragment == null) {
RecyclerViewFragment fragment = new RecyclerViewFragment();
- fragment.layoutManager = createLayoutManager(this);
- fragment.adapter = createAdapter();
+ initializeRecyclerViewFragment(fragment);
fm.beginTransaction().add(android.R.id.content, fragment).commit();
+ } else if (existingFragment instanceof RecyclerViewFragment) {
+ initializeRecyclerViewFragment((RecyclerViewFragment) existingFragment);
}
}
+ private void initializeRecyclerViewFragment(RecyclerViewFragment fragment) {
+ fragment.layoutManager = createLayoutManager(this);
+ fragment.adapter = createAdapter();
+ }
+
protected RecyclerView.LayoutManager createLayoutManager(Context context) {
return new LinearLayoutManager(context);
}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index eec3cdbe..8c2de40 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -52,7 +52,7 @@
doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
}
- private class TestPermissionChecker : NetworkStackConnector.PermissionChecker() {
+ private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
override fun enforceNetworkStackCallingPermission() = Unit
}
@@ -62,8 +62,8 @@
override fun sendNetworkConditionsBroadcast(context: Context, broadcast: Intent) = Unit
}
- private inner class TestNetworkStackConnector(context: Context) :
- NetworkStackConnector(context, TestPermissionChecker()) {
+ private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
+ context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
private val network = Network(TEST_NETID)
private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a992778..d2b26d3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -75,6 +75,7 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
@@ -6945,7 +6946,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(
android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -6961,7 +6962,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -6977,7 +6978,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -6994,7 +6995,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, network, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -7028,7 +7029,7 @@
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0);
+ mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -7050,7 +7051,7 @@
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0);
+ mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 23098ec..529d03c 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -547,6 +547,16 @@
@Test
public void testApplyTransportModeTransform() throws Exception {
+ verifyApplyTransportModeTransformCommon(false);
+ }
+
+ @Test
+ public void testApplyTransportModeTransformReleasedSpi() throws Exception {
+ verifyApplyTransportModeTransformCommon(true);
+ }
+
+ public void verifyApplyTransportModeTransformCommon(
+ boolean closeSpiBeforeApply) throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
addAuthAndCryptToIpSecConfig(ipSecConfig);
@@ -554,6 +564,39 @@
IpSecTransformResponse createTransformResp =
mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ if (closeSpiBeforeApply) {
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+ }
+
+ Socket socket = new Socket();
+ socket.bind(null);
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
+
+ int resourceId = createTransformResp.resourceId;
+ mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
+
+ verify(mMockNetd)
+ .ipSecApplyTransportModeTransform(
+ eq(pfd),
+ eq(mUid),
+ eq(IpSecManager.DIRECTION_OUT),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI));
+ }
+
+ @Test
+ public void testApplyTransportModeTransformWithClosedSpi() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+
+ // Close SPI record
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+
Socket socket = new Socket();
socket.bind(null);
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
@@ -660,6 +703,15 @@
@Test
public void testApplyTunnelModeTransform() throws Exception {
+ verifyApplyTunnelModeTransformCommon(false);
+ }
+
+ @Test
+ public void testApplyTunnelModeTransformReleasedSpi() throws Exception {
+ verifyApplyTunnelModeTransformCommon(true);
+ }
+
+ public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply) throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -670,6 +722,49 @@
IpSecTunnelInterfaceResponse createTunnelResp =
createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ if (closeSpiBeforeApply) {
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+ }
+
+ int transformResourceId = createTransformResp.resourceId;
+ int tunnelResourceId = createTunnelResp.resourceId;
+ mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
+ transformResourceId, "blessedPackage");
+
+ for (int selAddrFamily : ADDRESS_FAMILIES) {
+ verify(mMockNetd)
+ .ipSecUpdateSecurityPolicy(
+ eq(mUid),
+ eq(selAddrFamily),
+ eq(IpSecManager.DIRECTION_OUT),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI),
+ anyInt(), // iKey/oKey
+ anyInt(), // mask
+ eq(tunnelResourceId));
+ }
+
+ ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
+ }
+
+
+ @Test
+ public void testApplyTunnelModeTransformWithClosedSpi() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+
+ // Close SPI record
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+
int transformResourceId = createTransformResp.resourceId;
int tunnelResourceId = createTunnelResp.resourceId;
mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 24a8717..aafa18a 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -38,6 +38,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.os.Binder;
import android.os.INetworkManagementService;
import android.text.format.DateUtils;
@@ -354,7 +355,7 @@
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
- NetworkProvider.ID_NONE);
+ NetworkProvider.ID_NONE, Binder.getCallingUid());
nai.everValidated = true;
return nai;
}
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index fe0224a..ebe9b57 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -222,6 +222,10 @@
return sLoopers.get(test);
}
+ public static void remove(Object test) {
+ sLoopers.remove(test);
+ }
+
static class LooperFrameworkMethod extends FrameworkMethod {
private HandlerThread mHandlerThread;
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 0dd45ba..ea803f2 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -48,7 +48,8 @@
"android.view.InsetsStateTest",
"android.view.WindowMetricsTest",
"android.view.PendingInsetsControllerTest",
- "android.app.WindowContextTest"
+ "android.app.WindowContextTest",
+ "android.window.WindowMetricsHelperTest"
};
public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index bf886c2..3a3fb28 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1766,16 +1766,23 @@
return 1;
}
- // Determine the package name under which to merge resources.
- if (options_.rename_resources_package) {
- context_->SetCompilationPackage(options_.rename_resources_package.value());
- } else if (Maybe<AppInfo> maybe_app_info =
+ // First extract the Package name without modifying it (via --rename-manifest-package).
+ if (Maybe<AppInfo> maybe_app_info =
ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics())) {
- // Extract the package name from the manifest ignoring the value of --rename-manifest-package.
const AppInfo& app_info = maybe_app_info.value();
context_->SetCompilationPackage(app_info.package);
}
+ // Determine the package name under which to merge resources.
+ if (options_.rename_resources_package) {
+ if (!options_.custom_java_package) {
+ // Generate the R.java under the original package name instead of the package name specified
+ // through --rename-resources-package.
+ options_.custom_java_package = context_->GetCompilationPackage();
+ }
+ context_->SetCompilationPackage(options_.rename_resources_package.value());
+ }
+
// Now that the compilation package is set, load the dependencies. This will also extract
// the Android framework's versionCode and versionName, if they exist.
if (!LoadSymbolsFromIncludePaths()) {
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 556cf5e..f4c937c 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -124,13 +124,7 @@
// Print method body.
string indent("");
if (supportQ) {
- // TODO(b/146235828): Use just SDK_INT check once it is incremented from
- // Q.
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
- fprintf(out,
- " || (Build.VERSION.SDK_INT == "
- "Build.VERSION_CODES.Q\n");
- fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
+ fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n");
indent = " ";
}
diff --git a/tools/validatekeymaps/OWNERS b/tools/validatekeymaps/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/tools/validatekeymaps/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 6a8600a..1e2c81a 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -143,6 +143,16 @@
"framework-module-stubs-defaults-publicapi",
"framework-wifi-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-wifi.api.public.latest",
+ removed_api_file: ":framework-wifi-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-wifi.api.public.latest",
+ baseline_file: "api/lint-baseline.txt",
+ },
+ },
}
droidstubs {
@@ -151,6 +161,16 @@
"framework-module-stubs-defaults-systemapi",
"framework-wifi-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-wifi.api.system.latest",
+ removed_api_file: ":framework-wifi-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-wifi.api.system.latest",
+ baseline_file: "api/system-lint-baseline.txt",
+ },
+ },
}
droidstubs {
@@ -159,6 +179,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-wifi-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-wifi.api.module-lib.latest",
+ removed_api_file: ":framework-wifi-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-wifi.api.module-lib.latest",
+ },
+ },
}
droidstubs {
diff --git a/wifi/api/lint-baseline.txt b/wifi/api/lint-baseline.txt
new file mode 100644
index 0000000..892411f
--- /dev/null
+++ b/wifi/api/lint-baseline.txt
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+GenericException: android.net.wifi.WifiManager.LocalOnlyHotspotReservation#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.wifi.WifiManager.MulticastLock#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.wifi.WifiManager.WifiLock#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+
+
+VisiblySynchronized: PsiThisExpression:WifiManager.this:
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.net.wifi.WifiManager.WifiLock.finalize()
+VisiblySynchronized: android.net.wifi.WifiManager.WifiLock#finalize():
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.net.wifi.WifiManager.WifiLock.finalize()
diff --git a/wifi/api/system-lint-baseline.txt b/wifi/api/system-lint-baseline.txt
new file mode 100644
index 0000000..6547ee8
--- /dev/null
+++ b/wifi/api/system-lint-baseline.txt
@@ -0,0 +1,6 @@
+// Baseline format: 1.0
+MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+ android.net.wifi.rtt.RangingRequest does not declare a `getResponders()` method matching method android.net.wifi.rtt.RangingRequest.Builder.addResponder(android.net.wifi.rtt.ResponderConfig)
+
+MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index f5b5622..aa3a139 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -524,6 +524,161 @@
* {@hide}
*/
public final static int UNSPECIFIED = -1;
+
+ /**
+ * 2.4 GHz band first channel number
+ * @hide
+ */
+ public static final int BAND_24_GHZ_FIRST_CH_NUM = 1;
+ /**
+ * 2.4 GHz band last channel number
+ * @hide
+ */
+ public static final int BAND_24_GHZ_LAST_CH_NUM = 14;
+ /**
+ * 2.4 GHz band frequency of first channel in MHz
+ * @hide
+ */
+ public static final int BAND_24_GHZ_START_FREQ_MHZ = 2412;
+ /**
+ * 2.4 GHz band frequency of last channel in MHz
+ * @hide
+ */
+ public static final int BAND_24_GHZ_END_FREQ_MHZ = 2484;
+
+ /**
+ * 5 GHz band first channel number
+ * @hide
+ */
+ public static final int BAND_5_GHZ_FIRST_CH_NUM = 32;
+ /**
+ * 5 GHz band last channel number
+ * @hide
+ */
+ public static final int BAND_5_GHZ_LAST_CH_NUM = 173;
+ /**
+ * 5 GHz band frequency of first channel in MHz
+ * @hide
+ */
+ public static final int BAND_5_GHZ_START_FREQ_MHZ = 5160;
+ /**
+ * 5 GHz band frequency of last channel in MHz
+ * @hide
+ */
+ public static final int BAND_5_GHZ_END_FREQ_MHZ = 5865;
+
+ /**
+ * 6 GHz band first channel number
+ * @hide
+ */
+ public static final int BAND_6_GHZ_FIRST_CH_NUM = 1;
+ /**
+ * 6 GHz band last channel number
+ * @hide
+ */
+ public static final int BAND_6_GHZ_LAST_CH_NUM = 233;
+ /**
+ * 6 GHz band frequency of first channel in MHz
+ * @hide
+ */
+ public static final int BAND_6_GHZ_START_FREQ_MHZ = 5945;
+ /**
+ * 6 GHz band frequency of last channel in MHz
+ * @hide
+ */
+ public static final int BAND_6_GHZ_END_FREQ_MHZ = 7105;
+
+ /**
+ * Utility function to check if a frequency within 2.4 GHz band
+ * @param freqMhz frequency in MHz
+ * @return true if within 2.4GHz, false otherwise
+ *
+ * @hide
+ */
+ public static boolean is24GHz(int freqMhz) {
+ return freqMhz >= BAND_24_GHZ_START_FREQ_MHZ && freqMhz <= BAND_24_GHZ_END_FREQ_MHZ;
+ }
+
+ /**
+ * Utility function to check if a frequency within 5 GHz band
+ * @param freqMhz frequency in MHz
+ * @return true if within 5GHz, false otherwise
+ *
+ * @hide
+ */
+ public static boolean is5GHz(int freqMhz) {
+ return freqMhz >= BAND_5_GHZ_START_FREQ_MHZ && freqMhz <= BAND_5_GHZ_END_FREQ_MHZ;
+ }
+
+ /**
+ * Utility function to check if a frequency within 6 GHz band
+ * @param freqMhz
+ * @return true if within 6GHz, false otherwise
+ *
+ * @hide
+ */
+ public static boolean is6GHz(int freqMhz) {
+ return freqMhz >= BAND_6_GHZ_START_FREQ_MHZ && freqMhz <= BAND_6_GHZ_END_FREQ_MHZ;
+ }
+
+ /**
+ * Utility function to convert channel number/band to frequency in MHz
+ * @param channel number to convert
+ * @param band of channel to convert
+ * @return center frequency in Mhz of the channel, {@link UNSPECIFIED} if no match
+ *
+ * @hide
+ */
+ public static int convertChannelToFrequencyMhz(int channel, @WifiScanner.WifiBand int band) {
+ if (band == WifiScanner.WIFI_BAND_24_GHZ) {
+ // Special case
+ if (channel == 14) {
+ return 2484;
+ } else if (channel >= BAND_24_GHZ_FIRST_CH_NUM && channel <= BAND_24_GHZ_LAST_CH_NUM) {
+ return ((channel - BAND_24_GHZ_FIRST_CH_NUM) * 5) + BAND_24_GHZ_START_FREQ_MHZ;
+ } else {
+ return UNSPECIFIED;
+ }
+ }
+ if (band == WifiScanner.WIFI_BAND_5_GHZ) {
+ if (channel >= BAND_5_GHZ_FIRST_CH_NUM && channel <= BAND_5_GHZ_LAST_CH_NUM) {
+ return ((channel - BAND_5_GHZ_FIRST_CH_NUM) * 5) + BAND_5_GHZ_START_FREQ_MHZ;
+ } else {
+ return UNSPECIFIED;
+ }
+ }
+ if (band == WifiScanner.WIFI_BAND_6_GHZ) {
+ if (channel >= BAND_6_GHZ_FIRST_CH_NUM && channel <= BAND_6_GHZ_LAST_CH_NUM) {
+ return ((channel - BAND_6_GHZ_FIRST_CH_NUM) * 5) + BAND_6_GHZ_START_FREQ_MHZ;
+ } else {
+ return UNSPECIFIED;
+ }
+ }
+ return UNSPECIFIED;
+ }
+
+ /**
+ * Utility function to convert frequency in MHz to channel number
+ * @param freqMhz frequency in MHz
+ * @return channel number associated with given frequency, {@link UNSPECIFIED} if no match
+ *
+ * @hide
+ */
+ public static int convertFrequencyMhzToChannel(int freqMhz) {
+ // Special case
+ if (freqMhz == 2484) {
+ return 14;
+ } else if (is24GHz(freqMhz)) {
+ return (freqMhz - BAND_24_GHZ_START_FREQ_MHZ) / 5 + BAND_24_GHZ_FIRST_CH_NUM;
+ } else if (is5GHz(freqMhz)) {
+ return ((freqMhz - BAND_5_GHZ_START_FREQ_MHZ) / 5) + BAND_5_GHZ_FIRST_CH_NUM;
+ } else if (is6GHz(freqMhz)) {
+ return ((freqMhz - BAND_6_GHZ_START_FREQ_MHZ) / 5) + BAND_6_GHZ_FIRST_CH_NUM;
+ }
+
+ return UNSPECIFIED;
+ }
+
/**
* @hide
*/
@@ -533,14 +688,6 @@
/**
* @hide
- * TODO: makes real freq boundaries
- */
- public static boolean is24GHz(int freq) {
- return freq > 2400 && freq < 2500;
- }
-
- /**
- * @hide
*/
public boolean is5GHz() {
return ScanResult.is5GHz(frequency);
@@ -554,21 +701,6 @@
}
/**
- * @hide
- * TODO: makes real freq boundaries
- */
- public static boolean is5GHz(int freq) {
- return freq > 4900 && freq < 5900;
- }
-
- /**
- * @hide
- */
- public static boolean is6GHz(int freq) {
- return freq > 5925 && freq < 7125;
- }
-
- /**
* @hide
* anqp lines from supplicant BSS response
*/
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7d20d0d..5f46cb3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -817,6 +817,9 @@
/**
* Broadcast intent action indicating that the wifi network settings
* had been reset.
+ *
+ * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
+ * Intent will not be received by dynamically registered receivers.
* @hide
*/
@SystemApi
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index d299cdc..94771ac 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -131,10 +131,10 @@
public @interface WifiBand {}
/**
- * Max band value
+ * All bands
* @hide
*/
- public static final int WIFI_BAND_MAX = 0x10;
+ public static final int WIFI_BAND_ALL = (1 << WIFI_BAND_COUNT) - 1;
/** Minimum supported scanning period */
public static final int MIN_SCAN_PERIOD_MS = 1000;
@@ -168,6 +168,22 @@
}
/**
+ * Test if scan is a full scan. i.e. scanning all available bands.
+ * For backward compatibility, since some apps don't include 6GHz in their requests yet,
+ * lacking 6GHz band does not cause the result to be false.
+ *
+ * @param bandScanned bands that are fully scanned
+ * @param excludeDfs when true, DFS band is excluded from the check
+ * @return true if all bands are scanned, false otherwise
+ *
+ * @hide
+ */
+ public static boolean isFullBandScan(@WifiBand int bandScanned, boolean excludeDfs) {
+ return (bandScanned | WIFI_BAND_6_GHZ | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
+ == WIFI_BAND_ALL;
+ }
+
+ /**
* Returns a list of all the possible channels for the given band(s).
*
* @param band one of the WifiScanner#WIFI_BAND_* constants, e.g. {@link #WIFI_BAND_24_GHZ}
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index ea5043a..34e2e3a 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -30,9 +30,5 @@
<object type="module_controller"
class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
<option name="mainline-module-package-name" value="com.google.android.wifi" />
- <!-- TODO(b/151836001): com.android.wifi doesn't guarantee it is a Mainline module since
- it could still be OEM customized. Workaround so that this test will still run on
- AOSP builds. -->
- <option name="mainline-module-package-name" value="com.android.wifi" />
</object>
</configuration>
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index 6cb8324..5516f43 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -46,6 +46,68 @@
ScanResult.WIFI_STANDARD_11AC;
/**
+ * Frequency to channel map. This include some frequencies used outside the US.
+ * Representing it using a vector (instead of map) for simplification.
+ */
+ private static final int[] FREQUENCY_TO_CHANNEL_MAP = {
+ 2412, WifiScanner.WIFI_BAND_24_GHZ, 1,
+ 2417, WifiScanner.WIFI_BAND_24_GHZ, 2,
+ 2422, WifiScanner.WIFI_BAND_24_GHZ, 3,
+ 2427, WifiScanner.WIFI_BAND_24_GHZ, 4,
+ 2432, WifiScanner.WIFI_BAND_24_GHZ, 5,
+ 2437, WifiScanner.WIFI_BAND_24_GHZ, 6,
+ 2442, WifiScanner.WIFI_BAND_24_GHZ, 7,
+ 2447, WifiScanner.WIFI_BAND_24_GHZ, 8,
+ 2452, WifiScanner.WIFI_BAND_24_GHZ, 9,
+ 2457, WifiScanner.WIFI_BAND_24_GHZ, 10,
+ 2462, WifiScanner.WIFI_BAND_24_GHZ, 11,
+ /* 12, 13 are only legitimate outside the US. */
+ 2467, WifiScanner.WIFI_BAND_24_GHZ, 12,
+ 2472, WifiScanner.WIFI_BAND_24_GHZ, 13,
+ /* 14 is for Japan, DSSS and CCK only. */
+ 2484, WifiScanner.WIFI_BAND_24_GHZ, 14,
+ /* 34 valid in Japan. */
+ 5170, WifiScanner.WIFI_BAND_5_GHZ, 34,
+ 5180, WifiScanner.WIFI_BAND_5_GHZ, 36,
+ 5190, WifiScanner.WIFI_BAND_5_GHZ, 38,
+ 5200, WifiScanner.WIFI_BAND_5_GHZ, 40,
+ 5210, WifiScanner.WIFI_BAND_5_GHZ, 42,
+ 5220, WifiScanner.WIFI_BAND_5_GHZ, 44,
+ 5230, WifiScanner.WIFI_BAND_5_GHZ, 46,
+ 5240, WifiScanner.WIFI_BAND_5_GHZ, 48,
+ 5260, WifiScanner.WIFI_BAND_5_GHZ, 52,
+ 5280, WifiScanner.WIFI_BAND_5_GHZ, 56,
+ 5300, WifiScanner.WIFI_BAND_5_GHZ, 60,
+ 5320, WifiScanner.WIFI_BAND_5_GHZ, 64,
+ 5500, WifiScanner.WIFI_BAND_5_GHZ, 100,
+ 5520, WifiScanner.WIFI_BAND_5_GHZ, 104,
+ 5540, WifiScanner.WIFI_BAND_5_GHZ, 108,
+ 5560, WifiScanner.WIFI_BAND_5_GHZ, 112,
+ 5580, WifiScanner.WIFI_BAND_5_GHZ, 116,
+ /* 120, 124, 128 valid in Europe/Japan. */
+ 5600, WifiScanner.WIFI_BAND_5_GHZ, 120,
+ 5620, WifiScanner.WIFI_BAND_5_GHZ, 124,
+ 5640, WifiScanner.WIFI_BAND_5_GHZ, 128,
+ /* 132+ valid in US. */
+ 5660, WifiScanner.WIFI_BAND_5_GHZ, 132,
+ 5680, WifiScanner.WIFI_BAND_5_GHZ, 136,
+ 5700, WifiScanner.WIFI_BAND_5_GHZ, 140,
+ /* 144 is supported by a subset of WiFi chips. */
+ 5720, WifiScanner.WIFI_BAND_5_GHZ, 144,
+ 5745, WifiScanner.WIFI_BAND_5_GHZ, 149,
+ 5765, WifiScanner.WIFI_BAND_5_GHZ, 153,
+ 5785, WifiScanner.WIFI_BAND_5_GHZ, 157,
+ 5805, WifiScanner.WIFI_BAND_5_GHZ, 161,
+ 5825, WifiScanner.WIFI_BAND_5_GHZ, 165,
+ 5845, WifiScanner.WIFI_BAND_5_GHZ, 169,
+ 5865, WifiScanner.WIFI_BAND_5_GHZ, 173,
+ /* Now some 6GHz channels */
+ 5945, WifiScanner.WIFI_BAND_6_GHZ, 1,
+ 5960, WifiScanner.WIFI_BAND_6_GHZ, 4,
+ 6100, WifiScanner.WIFI_BAND_6_GHZ, 32
+ };
+
+ /**
* Setup before tests.
*/
@Before
@@ -184,6 +246,25 @@
}
/**
+ * verify frequency to channel conversion for all possible frequencies.
+ */
+ @Test
+ public void convertFrequencyToChannel() throws Exception {
+ for (int i = 0; i < FREQUENCY_TO_CHANNEL_MAP.length; i += 3) {
+ assertEquals(FREQUENCY_TO_CHANNEL_MAP[i + 2],
+ ScanResult.convertFrequencyMhzToChannel(FREQUENCY_TO_CHANNEL_MAP[i]));
+ }
+ }
+
+ /**
+ * Verify frequency to channel conversion failed for an invalid frequency.
+ */
+ @Test
+ public void convertFrequencyToChannelWithInvalidFreq() throws Exception {
+ assertEquals(-1, ScanResult.convertFrequencyMhzToChannel(8000));
+ }
+
+ /**
* Write the provided {@link ScanResult} to a parcel and deserialize it.
*/
private static ScanResult parcelReadWrite(ScanResult writeResult) throws Exception {
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index 4881200..b68616f 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -613,4 +613,22 @@
verify(mExecutor, never()).execute(any());
verify(mScanListener, never()).onResults(mScanData);
}
+
+ /**
+ * Tests isFullBandScan() method with and without DFS check
+ */
+ @Test
+ public void testIsFullBandScan() throws Exception {
+ assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_24_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_5_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_6_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(
+ WifiScanner.WIFI_BAND_6_GHZ | WifiScanner.WIFI_BAND_5_GHZ, true));
+ assertTrue(WifiScanner.isFullBandScan(
+ WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(
+ WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ, false));
+ assertTrue(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, true));
+ assertTrue(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, false));
+ }
}